Commit 8ed65601 for openh264
commit 8ed656019aab87820ffb876353db9e6a598b4d00
Author: BenzhengZhang <140143892+BenzhengZhang@users.noreply.github.com>
Date: Mon Aug 24 16:33:19 2026 +0800
processing: validate chroma strides before downsample (#3977)
* processing: validate chroma strides before downsample
* test: accept additional ParseOnly_General hash variant
* processing: scope chroma stride checks to downsample UV paths
* test: restore ParseOnly hash table to original DO NOT CHANGE values
* processing: avoid arm64 SAD symbol dependency in complexity analysis
* Revert "processing: avoid arm64 SAD symbol dependency in complexity analysis"
This reverts commit 888695e986ea45ed22d0adb401e1800629bd7858.
* processing: fix arm64 link by avoiding encoder SAD symbol
* processing: add local arm64 16x16 SAD and remove encoder symbol dependency
* processing: reject partial chroma planes in downsample validation
---------
Co-authored-by: benzzhan <benzzhan@cisco.com>
diff --git a/codec/processing/src/arm64/pixel_sad_aarch64_neon.S b/codec/processing/src/arm64/pixel_sad_aarch64_neon.S
index cf79116f..f8666f92 100644
--- a/codec/processing/src/arm64/pixel_sad_aarch64_neon.S
+++ b/codec/processing/src/arm64/pixel_sad_aarch64_neon.S
@@ -48,4 +48,22 @@ WELS_ASM_AARCH64_FUNC_BEGIN WelsProcessingSampleSad8x8_AArch64_neon
fmov w0, s2
WELS_ASM_AARCH64_FUNC_END
+//int32_t WelsProcessingSampleSad16x16_AArch64_neon (uint8_t*, int32_t, uint8_t*, int32_t);
+WELS_ASM_AARCH64_FUNC_BEGIN WelsProcessingSampleSad16x16_AArch64_neon
+ SIGN_EXTENSION x1, w1
+ SIGN_EXTENSION x3, w3
+ ld1 {v0.16b}, [x0], x1
+ ld1 {v1.16b}, [x2], x3
+ uabdl v2.8h, v0.8b, v1.8b
+ uabal2 v2.8h, v0.16b, v1.16b
+.rept 15
+ ld1 {v0.16b}, [x0], x1
+ ld1 {v1.16b}, [x2], x3
+ uabal v2.8h, v0.8b, v1.8b
+ uabal2 v2.8h, v0.16b, v1.16b
+.endr
+ saddlv s2, v2.8h
+ fmov w0, s2
+WELS_ASM_AARCH64_FUNC_END
+
#endif
diff --git a/codec/processing/src/common/WelsFrameWork.cpp b/codec/processing/src/common/WelsFrameWork.cpp
index 79e196b7..b67797a4 100644
--- a/codec/processing/src/common/WelsFrameWork.cpp
+++ b/codec/processing/src/common/WelsFrameWork.cpp
@@ -233,20 +233,34 @@ bool CVpFrameWork::CheckValid (EMethods eMethod, SPixMap& pSrcPixMap, SPixMap&
}
if (pSrcPixMap.pPixel[0]) {
+ const int32_t kiSrcChromaWidth = pSrcPixMap.sRect.iRectWidth >> 1;
if (pSrcPixMap.sRect.iRectWidth <= 0 || pSrcPixMap.sRect.iRectHeight <= 0
|| pSrcPixMap.sRect.iRectWidth * pSrcPixMap.sRect.iRectHeight > (MAX_MBS_PER_FRAME << 8))
goto exit;
if (pSrcPixMap.sRect.iRectTop >= pSrcPixMap.sRect.iRectHeight
|| pSrcPixMap.sRect.iRectLeft >= pSrcPixMap.sRect.iRectWidth || pSrcPixMap.sRect.iRectWidth > pSrcPixMap.iStride[0])
goto exit;
+ if (eMethod == METHOD_DOWNSAMPLE
+ && (pSrcPixMap.eFormat == VIDEO_FORMAT_I420 || pSrcPixMap.eFormat == VIDEO_FORMAT_YV12)
+ && (pSrcPixMap.pPixel[1] == NULL || pSrcPixMap.pPixel[2] == NULL
+ || pSrcPixMap.iStride[1] <= 0 || pSrcPixMap.iStride[2] <= 0
+ || kiSrcChromaWidth > pSrcPixMap.iStride[1] || kiSrcChromaWidth > pSrcPixMap.iStride[2]))
+ goto exit;
}
if (pDstPixMap.pPixel[0]) {
+ const int32_t kiDstChromaWidth = pDstPixMap.sRect.iRectWidth >> 1;
if (pDstPixMap.sRect.iRectWidth <= 0 || pDstPixMap.sRect.iRectHeight <= 0
|| pDstPixMap.sRect.iRectWidth * pDstPixMap.sRect.iRectHeight > (MAX_MBS_PER_FRAME << 8))
goto exit;
if (pDstPixMap.sRect.iRectTop >= pDstPixMap.sRect.iRectHeight
|| pDstPixMap.sRect.iRectLeft >= pDstPixMap.sRect.iRectWidth || pDstPixMap.sRect.iRectWidth > pDstPixMap.iStride[0])
goto exit;
+ if (eMethod == METHOD_DOWNSAMPLE
+ && (pDstPixMap.eFormat == VIDEO_FORMAT_I420 || pDstPixMap.eFormat == VIDEO_FORMAT_YV12)
+ && (pDstPixMap.pPixel[1] == NULL || pDstPixMap.pPixel[2] == NULL
+ || pDstPixMap.iStride[1] <= 0 || pDstPixMap.iStride[2] <= 0
+ || kiDstChromaWidth > pDstPixMap.iStride[1] || kiDstChromaWidth > pDstPixMap.iStride[2]))
+ goto exit;
}
eReturn = true;
diff --git a/codec/processing/src/common/common.h b/codec/processing/src/common/common.h
index 8016a094..e7d51508 100644
--- a/codec/processing/src/common/common.h
+++ b/codec/processing/src/common/common.h
@@ -76,6 +76,7 @@ WELSVP_EXTERN_C_END
#if defined(HAVE_NEON_AARCH64) && defined(__aarch64__)
WELSVP_EXTERN_C_BEGIN
int32_t WelsProcessingSampleSad8x8_AArch64_neon (uint8_t*, int32_t, uint8_t*, int32_t);
+int32_t WelsProcessingSampleSad16x16_AArch64_neon (uint8_t*, int32_t, uint8_t*, int32_t);
WELSVP_EXTERN_C_END
#endif
diff --git a/codec/processing/src/complexityanalysis/ComplexityAnalysis.cpp b/codec/processing/src/complexityanalysis/ComplexityAnalysis.cpp
index cd650276..f681d62c 100644
--- a/codec/processing/src/complexityanalysis/ComplexityAnalysis.cpp
+++ b/codec/processing/src/complexityanalysis/ComplexityAnalysis.cpp
@@ -296,7 +296,7 @@ CComplexityAnalysisScreen::CComplexityAnalysisScreen (int32_t iCpuFlag) {
#if defined (HAVE_NEON_AARCH64) && defined(__aarch64__)
if (iCpuFlag & WELS_CPU_NEON) {
- m_pSadFunc = WelsSampleSad16x16_AArch64_neon;
+ m_pSadFunc = WelsProcessingSampleSad16x16_AArch64_neon;
m_pIntraFunc[0] = WelsI16x16LumaPredV_AArch64_neon;
m_pIntraFunc[1] = WelsI16x16LumaPredH_AArch64_neon;
}
diff --git a/test/processing/ProcessUT_DownSample.cpp b/test/processing/ProcessUT_DownSample.cpp
index 9bac91dd..80b38b70 100644
--- a/test/processing/ProcessUT_DownSample.cpp
+++ b/test/processing/ProcessUT_DownSample.cpp
@@ -404,3 +404,67 @@ GENERATE_DyadicBilinearQuarterDownsampler_UT (DyadicBilinearQuarterDownsampler_A
GENERATE_GeneralBilinearDownsampler_UT (GeneralBilinearAccurateDownsamplerWrap_AArch64_neon,
GeneralBilinearAccurateDownsampler_ref, 1, WELS_CPU_NEON)
#endif
+
+TEST (DownSampleTest, VpFrameworkRejectsInvalidChromaStride) {
+ IWelsVP* pVp = NULL;
+ ASSERT_EQ (RET_SUCCESS, WelsCreateVpInterface ((void**) &pVp, WELSVP_INTERFACE_VERION));
+ ASSERT_TRUE (pVp != NULL);
+ ASSERT_EQ (RET_SUCCESS, pVp->Init (METHOD_DOWNSAMPLE, NULL));
+
+ uint8_t srcY[16 * 16] = { 0 };
+ uint8_t srcU[8 * 8] = { 0 };
+ uint8_t srcV[8 * 8] = { 0 };
+ uint8_t dstY[8 * 8] = { 0 };
+ uint8_t dstU[4 * 4] = { 0 };
+ uint8_t dstV[4 * 4] = { 0 };
+
+ SPixMap src;
+ SPixMap dst;
+ memset (&src, 0, sizeof (src));
+ memset (&dst, 0, sizeof (dst));
+
+ src.eFormat = VIDEO_FORMAT_I420;
+ src.pPixel[0] = srcY;
+ src.pPixel[1] = srcU;
+ src.pPixel[2] = srcV;
+ src.iStride[0] = 16;
+ src.iStride[1] = 0;
+ src.iStride[2] = 8;
+ src.sRect.iRectWidth = 16;
+ src.sRect.iRectHeight = 16;
+
+ dst.eFormat = VIDEO_FORMAT_I420;
+ dst.pPixel[0] = dstY;
+ dst.pPixel[1] = dstU;
+ dst.pPixel[2] = dstV;
+ dst.iStride[0] = 8;
+ dst.iStride[1] = 4;
+ dst.iStride[2] = 4;
+ dst.sRect.iRectWidth = 8;
+ dst.sRect.iRectHeight = 8;
+
+ EXPECT_EQ (RET_INVALIDPARAM, pVp->Process (METHOD_DOWNSAMPLE, &src, &dst));
+
+ src.iStride[1] = 8;
+ src.iStride[2] = 0;
+ EXPECT_EQ (RET_INVALIDPARAM, pVp->Process (METHOD_DOWNSAMPLE, &src, &dst));
+
+ src.iStride[1] = 8;
+ src.iStride[2] = 8;
+ src.pPixel[1] = NULL;
+ EXPECT_EQ (RET_INVALIDPARAM, pVp->Process (METHOD_DOWNSAMPLE, &src, &dst));
+
+ src.pPixel[1] = srcU;
+ src.pPixel[2] = NULL;
+ EXPECT_EQ (RET_INVALIDPARAM, pVp->Process (METHOD_DOWNSAMPLE, &src, &dst));
+
+ src.pPixel[2] = srcV;
+ dst.pPixel[1] = NULL;
+ EXPECT_EQ (RET_INVALIDPARAM, pVp->Process (METHOD_DOWNSAMPLE, &src, &dst));
+
+ dst.pPixel[1] = dstU;
+ dst.pPixel[2] = NULL;
+ EXPECT_EQ (RET_INVALIDPARAM, pVp->Process (METHOD_DOWNSAMPLE, &src, &dst));
+
+ EXPECT_EQ (RET_SUCCESS, WelsDestroyVpInterface (pVp, WELSVP_INTERFACE_VERION));
+}