aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYunqing Wang <yunqingwang@google.com>2023-12-04 17:32:51 -0800
committerJerome Jiang <jianj@google.com>2023-12-06 16:22:35 -0500
commitebca0ab6fa7862d3e511bf579446c5bc6f70bf4f (patch)
treecef7c2ff77c177795159aeeb98ebaeaa89a45bfc
parentffd533161ab3e95333351c977325ca615f9690c9 (diff)
downloadlibvpx-ebca0ab6fa7862d3e511bf579446c5bc6f70bf4f.tar.gz
Fix a bug in frame scaling
This change fixed a corner case bug reealed by b/311394513. During the frame scaling, vpx_highbd_convolve8() and vpx_scaled_2d() requires both x_step_q4 and y_step_q4 are less than or equal to a defined value. Otherwise, it needs to call vp9_scale_and_extend_ frame_nonnormative() that supports arbitrary scaling. The fix was done in LBD and HBD funnctions. Bug: b/311394513 Change-Id: Id0d34e7910ec98859030ef968ac19331488046d4 (cherry picked from commit 8bf3649d410cd68076e532e697f34dcec3f87ce7)
-rw-r--r--test/encode_api_test.cc19
-rw-r--r--vp9/encoder/vp9_encoder.c31
-rw-r--r--vp9/encoder/vp9_encoder.h8
-rw-r--r--vp9/encoder/vp9_frame_scale.c18
4 files changed, 69 insertions, 7 deletions
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index 3dfcc2ebf..dcbd15c80 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -782,6 +782,25 @@ TEST(EncodeAPI, Buganizer310329177) {
encoder.Encode(false);
}
+// This is a test case from clusterfuzz: based on b/311394513.
+// Encode a few frames with multiple change config calls
+// with different frame sizes.
+TEST(EncodeAPI, Buganizer311394513) {
+ VP9Encoder encoder(-7);
+
+ // Set initial config.
+ encoder.Configure(0, 5, 9, VPX_VBR, VPX_DL_REALTIME);
+
+ // Encode first frame.
+ encoder.Encode(false);
+
+ // Change config.
+ encoder.Configure(5, 2, 1, VPX_VBR, VPX_DL_REALTIME);
+
+ // Encode 2nd frame with new config.
+ encoder.Encode(true);
+}
+
class EncodeApiGetTplStatsTest
: public ::libvpx_test::EncoderTest,
public ::testing::TestWithParam<const libvpx_test::CodecFactory *> {
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index be5515014..20e35077c 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -3079,12 +3079,11 @@ void vp9_write_yuv_rec_frame(VP9_COMMON *cm) {
#endif
#if CONFIG_VP9_HIGHBITDEPTH
-static void scale_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src,
- YV12_BUFFER_CONFIG *dst,
- int bd) {
+void vp9_scale_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src,
+ YV12_BUFFER_CONFIG *dst, int bd) {
#else
-static void scale_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src,
- YV12_BUFFER_CONFIG *dst) {
+void vp9_scale_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src,
+ YV12_BUFFER_CONFIG *dst) {
#endif // CONFIG_VP9_HIGHBITDEPTH
// TODO(dkovalev): replace YV12_BUFFER_CONFIG with vpx_image_t
int i;
@@ -3129,6 +3128,23 @@ static void scale_and_extend_frame(const YV12_BUFFER_CONFIG *src,
const int src_h = src->y_crop_height;
const int dst_w = dst->y_crop_width;
const int dst_h = dst->y_crop_height;
+
+ // The issue b/311394513 reveals a corner case bug.
+ // For bd = 8, vpx_scaled_2d() requires both x_step_q4 and y_step_q4 are less
+ // than or equal to 64. For bd >= 10, vpx_highbd_convolve8() requires both
+ // x_step_q4 and y_step_q4 are less than or equal to 32. If this condition
+ // isn't met, it needs to call vp9_scale_and_extend_frame_nonnormative() that
+ // supports arbitrary scaling.
+ const int x_step_q4 = 16 * src_w / dst_w;
+ const int y_step_q4 = 16 * src_h / dst_h;
+ const int is_arbitrary_scaling =
+ (bd == 8 && (x_step_q4 > 64 || y_step_q4 > 64)) ||
+ (bd >= 10 && (x_step_q4 > 32 || y_step_q4 > 32));
+ if (is_arbitrary_scaling) {
+ vp9_scale_and_extend_frame_nonnormative(src, dst, bd);
+ return;
+ }
+
const uint8_t *const srcs[3] = { src->y_buffer, src->u_buffer,
src->v_buffer };
const int src_strides[3] = { src->y_stride, src->uv_stride, src->uv_stride };
@@ -4993,13 +5009,14 @@ YV12_BUFFER_CONFIG *vp9_scale_if_required(
scale_and_extend_frame(unscaled, scaled, (int)cm->bit_depth,
filter_type, phase_scaler);
else
- scale_and_extend_frame_nonnormative(unscaled, scaled, (int)cm->bit_depth);
+ vp9_scale_and_extend_frame_nonnormative(unscaled, scaled,
+ (int)cm->bit_depth);
#else
if (use_normative_scaler && unscaled->y_width <= (scaled->y_width << 1) &&
unscaled->y_height <= (scaled->y_height << 1))
vp9_scale_and_extend_frame(unscaled, scaled, filter_type, phase_scaler);
else
- scale_and_extend_frame_nonnormative(unscaled, scaled);
+ vp9_scale_and_extend_frame_nonnormative(unscaled, scaled);
#endif // CONFIG_VP9_HIGHBITDEPTH
return scaled;
} else {
diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h
index 160de0064..83b7081e7 100644
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -1382,6 +1382,14 @@ void vp9_get_ref_frame_info(FRAME_UPDATE_TYPE update_type, int ref_frame_flags,
void vp9_set_high_precision_mv(VP9_COMP *cpi, int allow_high_precision_mv);
+#if CONFIG_VP9_HIGHBITDEPTH
+void vp9_scale_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src,
+ YV12_BUFFER_CONFIG *dst, int bd);
+#else
+void vp9_scale_and_extend_frame_nonnormative(const YV12_BUFFER_CONFIG *src,
+ YV12_BUFFER_CONFIG *dst);
+#endif // CONFIG_VP9_HIGHBITDEPTH
+
YV12_BUFFER_CONFIG *vp9_svc_twostage_scale(
VP9_COMMON *cm, YV12_BUFFER_CONFIG *unscaled, YV12_BUFFER_CONFIG *scaled,
YV12_BUFFER_CONFIG *scaled_temp, INTERP_FILTER filter_type,
diff --git a/vp9/encoder/vp9_frame_scale.c b/vp9/encoder/vp9_frame_scale.c
index a410d0407..22b3f0557 100644
--- a/vp9/encoder/vp9_frame_scale.c
+++ b/vp9/encoder/vp9_frame_scale.c
@@ -12,6 +12,7 @@
#include "./vpx_dsp_rtcd.h"
#include "./vpx_scale_rtcd.h"
#include "vp9/common/vp9_blockd.h"
+#include "vp9/encoder/vp9_encoder.h"
#include "vpx_dsp/vpx_filter.h"
#include "vpx_scale/yv12config.h"
@@ -91,6 +92,23 @@ void vp9_scale_and_extend_frame_c(const YV12_BUFFER_CONFIG *src,
{
const int dst_w = dst->y_crop_width;
const int dst_h = dst->y_crop_height;
+
+ // The issue b/311394513 reveals a corner case bug. vpx_scaled_2d() requires
+ // both x_step_q4 and y_step_q4 are less than or equal to 64. Otherwise, it
+ // needs to call vp9_scale_and_extend_frame_nonnormative() that supports
+ // arbitrary scaling.
+ const int x_step_q4 = 16 * src_w / dst_w;
+ const int y_step_q4 = 16 * src_h / dst_h;
+ if (x_step_q4 > 64 || y_step_q4 > 64) {
+ // This funnction is only called while cm->bit_depth is VPX_BITS_8.
+#if CONFIG_VP9_HIGHBITDEPTH
+ vp9_scale_and_extend_frame_nonnormative(src, dst, (int)VPX_BITS_8);
+#else
+ vp9_scale_and_extend_frame_nonnormative(src, dst);
+#endif // CONFIG_VP9_HIGHBITDEPTH
+ return;
+ }
+
for (i = 0; i < MAX_MB_PLANE; ++i) {
const int factor = (i == 0 || i == 3 ? 1 : 2);
const int src_stride = src_strides[i];