From a6d2b2afa63d0a89660c0928d8a263b4d6a2175a Mon Sep 17 00:00:00 2001 From: Luis Horna Carranza Date: Wed, 23 Sep 2026 13:25:17 -0500 Subject: [PATCH 1/4] Fix incorrect stride for buffer access Use the destination stride when accessing the destination buffer in copy_mem64x64 and rd_pick_intra4x4block. Add a copy_mem64x64 regression test that uses a 16x16 checkerboard and frame buffers with different strides. Change-Id: I3bf8b6232185a76236d879b1c6726192a0faccac --- test/mfqe_test.cc | 144 ++++++++++++++++++++++++++++++++++++++++ test/test.mk | 3 + vp9/common/vp9_mfqe.c | 4 +- vp9/encoder/vp9_rdopt.c | 2 +- 4 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 test/mfqe_test.cc diff --git a/test/mfqe_test.cc b/test/mfqe_test.cc new file mode 100644 index 00000000000..351daa87ec6 --- /dev/null +++ b/test/mfqe_test.cc @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2026 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "vpx_config.h" +#include "vp9/common/vp9_mfqe.h" +#include "vp9/common/vp9_onyxc_int.h" +#include "vpx_scale/yv12config.h" + +namespace { + +constexpr int kFrameSize = 64; +constexpr int kCheckerboardSquareSize = 4; + +class TmpFrameBuffer { + public: + // Returns an initialized frame, or nullptr if allocation fails. + static std::unique_ptr Create(int width, int height, + int stride, + bool fill_checkerboard); + + TmpFrameBuffer(const TmpFrameBuffer &) = delete; + TmpFrameBuffer &operator=(const TmpFrameBuffer &) = delete; + ~TmpFrameBuffer() { vpx_free_frame_buffer(&buffer_); } + + // Returns a borrowed reference valid for this object's lifetime. + YV12_BUFFER_CONFIG &buffer() { return buffer_; } + + private: + // Takes ownership of buffer's allocation. + explicit TmpFrameBuffer(const YV12_BUFFER_CONFIG &buffer) : buffer_(buffer) {} + + YV12_BUFFER_CONFIG buffer_ = {}; +}; + +std::unique_ptr TmpFrameBuffer::Create(int width, int height, + int stride, + bool fill_checkerboard) { + YV12_BUFFER_CONFIG buffer = {}; +#if CONFIG_VP9_HIGHBITDEPTH + const int allocation_status = + vpx_alloc_frame_buffer(&buffer, stride, height, 1, 1, 0, 0, 0); +#else + const int allocation_status = + vpx_alloc_frame_buffer(&buffer, stride, height, 1, 1, 0, 0); +#endif + if (allocation_status != 0) return nullptr; + + buffer.y_width = width; + buffer.y_height = height; + buffer.y_crop_width = width; + buffer.y_crop_height = height; + buffer.uv_width = width >> 1; + buffer.uv_height = height >> 1; + buffer.uv_crop_width = width >> 1; + buffer.uv_crop_height = height >> 1; + buffer.render_width = width; + buffer.render_height = height; + + if (fill_checkerboard) { + // Fill the luma plane with a checkerboard pattern. + for (int row = 0; row < height; ++row) { + for (int col = 0; col < width; ++col) { + const int checkerboard_row = row / kCheckerboardSquareSize; + const int checkerboard_col = col / kCheckerboardSquareSize; + int pixel_value = 0x20; + if ((checkerboard_row + checkerboard_col) % 2 != 0) { + pixel_value = 0xe0; + } + buffer.y_buffer[row * buffer.y_stride + col] = pixel_value; + } + } + } else { + // Use a distinct initial luma value so copying is observable. + for (int row = 0; row < height; ++row) { + memset(buffer.y_buffer + row * buffer.y_stride, 0, width); + } + } + + // Use neutral chroma so the checkerboard pattern is luma-only. + for (int row = 0; row < height / 2; ++row) { + memset(buffer.u_buffer + row * buffer.uv_stride, 0x80, width / 2); + memset(buffer.v_buffer + row * buffer.uv_stride, 0x80, width / 2); + } + std::unique_ptr frame(new (std::nothrow) + TmpFrameBuffer(buffer)); + if (frame == nullptr) { + vpx_free_frame_buffer(&buffer); + } + return frame; +} + +TEST(MfqeTest, Copy64x64WithDifferentStrides) { + auto source = TmpFrameBuffer::Create(kFrameSize, kFrameSize, kFrameSize, + /*fill_checkerboard=*/true); + ASSERT_NE(source, nullptr); + // The wider allocation produces a different stride while preserving the + // visible dimensions of the image. + auto destination = + TmpFrameBuffer::Create(kFrameSize, kFrameSize, kFrameSize + 16, + /*fill_checkerboard=*/false); + ASSERT_NE(destination, nullptr); + ASSERT_NE(source->buffer().y_stride, destination->buffer().y_stride); + + // One MODE_INFO entry per 8x8 MI unit in this 64x64 superblock. + std::array mi = {}; + mi[0].sb_type = BLOCK_64X64; + mi[0].mode = DC_PRED; // Force the copy path rather than MFQE filtering. + + VP9_COMMON cm = {}; + cm.frame_type = INTER_FRAME; + cm.frame_to_show = &source->buffer(); + cm.post_proc_buffer = destination->buffer(); + cm.mi_rows = MI_BLOCK_SIZE; + cm.mi_cols = MI_BLOCK_SIZE; + cm.mi_stride = MI_BLOCK_SIZE; + cm.mi = mi.data(); + + vp9_mfqe(&cm); + + for (int row = 0; row < kFrameSize; ++row) { + EXPECT_EQ( + std::memcmp( + source->buffer().y_buffer + row * source->buffer().y_stride, + cm.post_proc_buffer.y_buffer + row * cm.post_proc_buffer.y_stride, + kFrameSize), + 0) + << "row " << row; + } +} + +} // namespace diff --git a/test/test.mk b/test/test.mk index 47860e6f751..ef859927cda 100644 --- a/test/test.mk +++ b/test/test.mk @@ -186,6 +186,9 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_tokenize_test.cc LIBVPX_TEST_SRCS-yes += vp9_intrapred_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += vp9_decrypt_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += vp9_thread_test.cc +ifeq ($(CONFIG_VP9_DECODER)$(CONFIG_VP9_POSTPROC),yesyes) +LIBVPX_TEST_SRCS-yes += mfqe_test.cc +endif LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += avg_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += comp_avg_pred_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct16x16_test.cc diff --git a/vp9/common/vp9_mfqe.c b/vp9/common/vp9_mfqe.c index 18fab6a9a94..2530f4b0536 100644 --- a/vp9/common/vp9_mfqe.c +++ b/vp9/common/vp9_mfqe.c @@ -119,10 +119,10 @@ static void copy_mem64x64(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride) { copy_mem32x32(src, src_stride, dst, dst_stride); copy_mem32x32(src + 32, src_stride, dst + 32, dst_stride); - copy_mem32x32(src + src_stride * 32, src_stride, dst + src_stride * 32, + copy_mem32x32(src + src_stride * 32, src_stride, dst + dst_stride * 32, dst_stride); copy_mem32x32(src + src_stride * 32 + 32, src_stride, - dst + src_stride * 32 + 32, dst_stride); + dst + dst_stride * 32 + 32, dst_stride); } static void copy_block(const uint8_t *y, const uint8_t *u, const uint8_t *v, diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 9ad769ee641..67df294ed2f 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -1072,7 +1072,7 @@ static int64_t rd_pick_intra4x4block(VP9_COMP *cpi, MACROBLOCK *x, int row, const int src_stride = p->src.stride; const int dst_stride = pd->dst.stride; const uint8_t *src_init = &p->src.buf[row * 4 * src_stride + col * 4]; - uint8_t *dst_init = &pd->dst.buf[row * 4 * src_stride + col * 4]; + uint8_t *dst_init = &pd->dst.buf[row * 4 * dst_stride + col * 4]; ENTROPY_CONTEXT ta[2], tempa[2]; ENTROPY_CONTEXT tl[2], templ[2]; const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize]; From deaac25491db2edc430c2a71031109b65c23d1f1 Mon Sep 17 00:00:00 2001 From: Marco Paniconi Date: Mon, 28 Sep 2026 17:58:01 +0000 Subject: [PATCH 2/4] vp8: Validate ss_number_layers and factor den in validate_config Add range checks in vp8 validate_config() for ss_number_layers (1..VPX_SS_MAX_LAYERS) and kf_frame_max_boost_first_factor.den, and perform all scalar config range checks before dereferencing rc_twopass_stats_in.buf when g_pass == VPX_RC_LAST_PASS. Add unittest. Bug: 564326761 Change-Id: I57edc6e3f8b51caf666bc40ea20352c2b2b01e64 --- test/encode_api_test.cc | 48 +++++++++++++++++++++++++++++++++++++ vp8/vp8_cx_iface.c | 52 +++++++++++++++++++++++------------------ 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc index 73baf0c0e3a..3c98e9cd41b 100644 --- a/test/encode_api_test.cc +++ b/test/encode_api_test.cc @@ -572,6 +572,54 @@ TEST(EncodeAPI, SetReferenceSizeValidationVp8) { EXPECT_EQ(vpx_codec_destroy(&enc), VPX_CODEC_OK); } +// Bug: 564326761. +TEST(EncodeAPI, ValidateConfigVp8) { + vpx_codec_iface_t *const iface = vpx_codec_vp8_cx(); + vpx_codec_enc_cfg_t default_cfg; + ASSERT_EQ(vpx_codec_enc_config_default(iface, &default_cfg, 0), VPX_CODEC_OK); + + const vpx_rational_t dsf = { 1, 1 }; + vpx_codec_ctx_t enc = {}; + + // Invalid ss_number_layers (0 and > VPX_SS_MAX_LAYERS). + for (const unsigned int layers : { 0U, VPX_SS_MAX_LAYERS + 1U }) { + vpx_codec_enc_cfg_t cfg = default_cfg; + cfg.ss_number_layers = layers; + EXPECT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), + VPX_CODEC_INVALID_PARAM); + EXPECT_EQ(vpx_codec_enc_init_multi(&enc, iface, &cfg, 1, 0, &dsf), + VPX_CODEC_INVALID_PARAM); + } + + // Invalid boost factor denominators (0). + { + vpx_codec_enc_cfg_t cfg = default_cfg; + cfg.kf_frame_max_boost_first_factor.den = 0; + EXPECT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), + VPX_CODEC_INVALID_PARAM); + } + { + vpx_codec_enc_cfg_t cfg = default_cfg; + cfg.kf_max_total_boost_factor.den = 0; + EXPECT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), + VPX_CODEC_INVALID_PARAM); + } + + // Ensure scalar range checks run before dereferencing rc_twopass_stats_in.buf + // when g_pass == VPX_RC_LAST_PASS. + { + uint8_t dummy_buf[1] = { 0 }; + constexpr size_t kDummyStatsSize = 52992; + vpx_codec_enc_cfg_t cfg = default_cfg; + cfg.g_pass = VPX_RC_LAST_PASS; + cfg.ss_number_layers = VPX_SS_MAX_LAYERS + 1; + cfg.rc_twopass_stats_in.buf = dummy_buf; + cfg.rc_twopass_stats_in.sz = kDummyStatsSize; + EXPECT_EQ(vpx_codec_enc_init_multi(&enc, iface, &cfg, 1, 0, &dsf), + VPX_CODEC_INVALID_PARAM); + } +} + // Emulates the WebCodecs VideoEncoder interface. class VP8Encoder { public: diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index 19754fcf5c2..e92e58c0ba6 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -222,29 +222,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(vp8_cfg, cq_level, cfg->rc_min_quantizer, cfg->rc_max_quantizer); -#if !(CONFIG_REALTIME_ONLY) - if (cfg->g_pass == VPX_RC_LAST_PASS) { - size_t packet_sz = sizeof(FIRSTPASS_STATS); - int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz); - FIRSTPASS_STATS *stats; - - if (!cfg->rc_twopass_stats_in.buf) - ERROR("rc_twopass_stats_in.buf not set."); - - if (cfg->rc_twopass_stats_in.sz % packet_sz) - ERROR("rc_twopass_stats_in.sz indicates truncated packet."); - - if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz) - ERROR("rc_twopass_stats_in requires at least two packets."); - - stats = (void *)((char *)cfg->rc_twopass_stats_in.buf + - (n_packets - 1) * packet_sz); - - if ((int)(stats->count + 0.5) != n_packets - 1) - ERROR("rc_twopass_stats_in missing EOS stats packet"); - } -#endif - + RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS); RANGE_CHECK(cfg, ts_number_layers, 1, 5); if (cfg->ts_number_layers > 1) { @@ -281,6 +259,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(cfg, sr_diff_factor.den, 1, 1000); RANGE_CHECK(cfg, kf_err_per_mb_factor.den, 1, 1000); RANGE_CHECK(cfg, kf_frame_min_boost_factor.den, 1, 1000); + RANGE_CHECK(cfg, kf_frame_max_boost_first_factor.den, 1, 1000); RANGE_CHECK(cfg, kf_frame_max_boost_subs_factor.den, 1, 1000); RANGE_CHECK(cfg, kf_max_total_boost_factor.den, 1, 1000); RANGE_CHECK(cfg, gf_max_total_boost_factor.den, 1, 1000); @@ -290,6 +269,33 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(cfg, rd_mult_arf_qp_fac.den, 1, 1000); RANGE_CHECK(cfg, rd_mult_key_qp_fac.den, 1, 1000); +#if !(CONFIG_REALTIME_ONLY) + if (cfg->g_pass == VPX_RC_LAST_PASS) { + const size_t packet_sz = sizeof(FIRSTPASS_STATS); + const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz); + const FIRSTPASS_STATS *stats; + + if (!cfg->rc_twopass_stats_in.buf) { + ERROR("rc_twopass_stats_in.buf not set."); + } + + if (cfg->rc_twopass_stats_in.sz % packet_sz) { + ERROR("rc_twopass_stats_in.sz indicates truncated packet."); + } + + if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz) { + ERROR("rc_twopass_stats_in requires at least two packets."); + } + + stats = + (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf + n_packets - 1; + + if ((int)(stats->count + 0.5) != n_packets - 1) { + ERROR("rc_twopass_stats_in missing EOS stats packet"); + } + } +#endif + return VPX_CODEC_OK; } From 021170248a2928c7af57444db8b18bcfe97cbe48 Mon Sep 17 00:00:00 2001 From: Philipp Hancke Date: Sun, 27 Sep 2026 12:00:53 +0200 Subject: [PATCH 3/4] vp8: document handling of corrupt frames vpx_codec_decode() can return VPX_CODEC_OK for a corrupted VP8 frame, e.g. when data is missing from the last token partition. Document that callers must query VP8D_GET_FRAME_CORRUPTED after every decode. Bug: chromium:561396583 Change-Id: I07f1e495e81a1ff51bf2502b7a64b8c1744bb764 --- examples/simple_decoder.c | 9 ++++++++- vpx/vp8dx.h | 7 ++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/examples/simple_decoder.c b/examples/simple_decoder.c index d089e826d5b..542f07371c4 100644 --- a/examples/simple_decoder.c +++ b/examples/simple_decoder.c @@ -73,12 +73,15 @@ // This example does not special case any error return codes. If there was // an error, a descriptive message is printed and the program exits. With // few exceptions, vpx_codec functions return an enumerated error status, -// with the value `0` indicating success. +// with the value `0` indicating success. VP8 may return success for a +// corrupted frame, so the VP8D_GET_FRAME_CORRUPTED control is checked after +// every decode. #include #include #include +#include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" #include "../tools_common.h" @@ -124,10 +127,14 @@ int main(int argc, char **argv) { vpx_codec_iter_t iter = NULL; vpx_image_t *img = NULL; size_t frame_size = 0; + int corrupted = 0; const unsigned char *frame = vpx_video_reader_get_frame(reader, &frame_size); if (vpx_codec_decode(&codec, frame, (unsigned int)frame_size, NULL, 0)) die_codec(&codec, "Failed to decode frame."); + if (vpx_codec_control(&codec, VP8D_GET_FRAME_CORRUPTED, &corrupted)) + die_codec(&codec, "Failed to get frame corrupted state."); + if (corrupted) die("Frame %d is corrupted.", frame_cnt); while ((img = vpx_codec_get_frame(&codec, &iter)) != NULL) { vpx_img_write(img, outfile); diff --git a/vpx/vp8dx.h b/vpx/vp8dx.h index 8c13649f4a1..49e67172a7e 100644 --- a/vpx/vp8dx.h +++ b/vpx/vp8dx.h @@ -75,7 +75,12 @@ enum vp8_dec_control_id { */ VP8D_GET_LAST_REF_UPDATES = VP8_DECODER_CTRL_ID_START, - /** check if the indicated frame is corrupted */ + /** check if the last decoded frame is corrupted. For VP8, + * vpx_codec_decode() may return VPX_CODEC_OK for a corrupted frame, so this + * must be checked after every decode. This happens when data is missing + * from the last token partition, whose size is implicit, or when the frame + * references a corrupted frame. + */ VP8D_GET_FRAME_CORRUPTED, /** control function to get info on which reference frames were used From 91fe2b1a9543a7aee713b83876b541beb8eb3eed Mon Sep 17 00:00:00 2001 From: Kalt2212 <107548841+kalt2212@users.noreply.github.com> Date: Wed, 30 Sep 2026 11:26:13 +0200 Subject: [PATCH 4/4] vp9: Validate kf_frame_max_boost_first_factor.den in validate_config Port the VP8 fix from deaac25 (Bug 564326761) to the VP9 encoder. validate_config() checked .den in [1,1000] for 14 rational config factors but not kf_frame_max_boost_first_factor.den, which is used as a divisor when setting up two-pass rate control; den=0 yields inf/NaN in kf_frame_max_boost_first. Also perform all scalar config range checks before dereferencing rc_twopass_stats_in.buf for VPX_RC_LAST_PASS, matching the VP8 ordering. Add EncodeAPI.ValidateConfigVp9 unittest. --- test/encode_api_test.cc | 21 +++++++++++++ vp9/vp9_cx_iface.c | 67 +++++++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 33 deletions(-) diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc index 3c98e9cd41b..8781787372d 100644 --- a/test/encode_api_test.cc +++ b/test/encode_api_test.cc @@ -1159,6 +1159,27 @@ TEST(EncodeAPI, Vp8SSIMMultipleFrames) { } #endif // CONFIG_VP8_ENCODER +#if CONFIG_VP9_ENCODER +// Ports the VP8 fix for Bug 564326761 to VP9: validate +// kf_frame_max_boost_first_factor.den before use as a divisor. +TEST(EncodeAPI, ValidateConfigVp9) { + vpx_codec_iface_t *const iface = vpx_codec_vp9_cx(); + vpx_codec_enc_cfg_t default_cfg; + ASSERT_EQ(vpx_codec_enc_config_default(iface, &default_cfg, 0), VPX_CODEC_OK); + + vpx_codec_ctx_t enc = {}; + + // Invalid boost factor denominator (0). + { + vpx_codec_enc_cfg_t cfg = default_cfg; + cfg.kf_frame_max_boost_first_factor.den = 0; + EXPECT_EQ(vpx_codec_enc_init(&enc, iface, &cfg, 0), + VPX_CODEC_INVALID_PARAM); + } +} + +#endif // CONFIG_VP9_ENCODER + // Set up 2 spatial streams with 2 temporal layers per stream, and generate // invalid configuration by setting the temporal layer rate allocation // (ts_target_bitrate[]) to 0 for both layers. This should fail independent of diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index 47603e17e61..bc3823e7349 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -303,6 +303,40 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(extra_cfg, content, VP9E_CONTENT_DEFAULT, VP9E_CONTENT_INVALID - 1); +#if !CONFIG_VP9_HIGHBITDEPTH + if (cfg->g_profile > (unsigned int)PROFILE_1) { + ERROR("Profile > 1 not supported in this build configuration"); + } +#endif + if (cfg->g_profile <= (unsigned int)PROFILE_1 && + cfg->g_bit_depth > VPX_BITS_8) { + ERROR("Codec high bit-depth not supported in profile < 2"); + } + if (cfg->g_profile > (unsigned int)PROFILE_1 && + cfg->g_bit_depth == VPX_BITS_8) { + ERROR("Codec bit-depth 8 not supported in profile > 1"); + } + RANGE_CHECK(extra_cfg, color_space, VPX_CS_UNKNOWN, VPX_CS_SRGB); + RANGE_CHECK(extra_cfg, color_range, VPX_CR_STUDIO_RANGE, VPX_CR_FULL_RANGE); + + // The range below shall be further tuned. + RANGE_CHECK(cfg, use_vizier_rc_params, 0, 1); + RANGE_CHECK(cfg, active_wq_factor.den, 1, 1000); + RANGE_CHECK(cfg, err_per_mb_factor.den, 1, 1000); + RANGE_CHECK(cfg, sr_default_decay_limit.den, 1, 1000); + RANGE_CHECK(cfg, sr_diff_factor.den, 1, 1000); + RANGE_CHECK(cfg, kf_err_per_mb_factor.den, 1, 1000); + RANGE_CHECK(cfg, kf_frame_min_boost_factor.den, 1, 1000); + RANGE_CHECK(cfg, kf_frame_max_boost_first_factor.den, 1, 1000); + RANGE_CHECK(cfg, kf_frame_max_boost_subs_factor.den, 1, 1000); + RANGE_CHECK(cfg, kf_max_total_boost_factor.den, 1, 1000); + RANGE_CHECK(cfg, gf_max_total_boost_factor.den, 1, 1000); + RANGE_CHECK(cfg, gf_frame_max_boost_factor.den, 1, 1000); + RANGE_CHECK(cfg, zm_factor.den, 1, 1000); + RANGE_CHECK(cfg, rd_mult_inter_qp_fac.den, 1, 1000); + RANGE_CHECK(cfg, rd_mult_arf_qp_fac.den, 1, 1000); + RANGE_CHECK(cfg, rd_mult_key_qp_fac.den, 1, 1000); + #if !CONFIG_REALTIME_ONLY if (cfg->g_pass == VPX_RC_LAST_PASS) { const size_t packet_sz = sizeof(FIRSTPASS_STATS); @@ -362,39 +396,6 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, } #endif // !CONFIG_REALTIME_ONLY -#if !CONFIG_VP9_HIGHBITDEPTH - if (cfg->g_profile > (unsigned int)PROFILE_1) { - ERROR("Profile > 1 not supported in this build configuration"); - } -#endif - if (cfg->g_profile <= (unsigned int)PROFILE_1 && - cfg->g_bit_depth > VPX_BITS_8) { - ERROR("Codec high bit-depth not supported in profile < 2"); - } - if (cfg->g_profile > (unsigned int)PROFILE_1 && - cfg->g_bit_depth == VPX_BITS_8) { - ERROR("Codec bit-depth 8 not supported in profile > 1"); - } - RANGE_CHECK(extra_cfg, color_space, VPX_CS_UNKNOWN, VPX_CS_SRGB); - RANGE_CHECK(extra_cfg, color_range, VPX_CR_STUDIO_RANGE, VPX_CR_FULL_RANGE); - - // The range below shall be further tuned. - RANGE_CHECK(cfg, use_vizier_rc_params, 0, 1); - RANGE_CHECK(cfg, active_wq_factor.den, 1, 1000); - RANGE_CHECK(cfg, err_per_mb_factor.den, 1, 1000); - RANGE_CHECK(cfg, sr_default_decay_limit.den, 1, 1000); - RANGE_CHECK(cfg, sr_diff_factor.den, 1, 1000); - RANGE_CHECK(cfg, kf_err_per_mb_factor.den, 1, 1000); - RANGE_CHECK(cfg, kf_frame_min_boost_factor.den, 1, 1000); - RANGE_CHECK(cfg, kf_frame_max_boost_subs_factor.den, 1, 1000); - RANGE_CHECK(cfg, kf_max_total_boost_factor.den, 1, 1000); - RANGE_CHECK(cfg, gf_max_total_boost_factor.den, 1, 1000); - RANGE_CHECK(cfg, gf_frame_max_boost_factor.den, 1, 1000); - RANGE_CHECK(cfg, zm_factor.den, 1, 1000); - RANGE_CHECK(cfg, rd_mult_inter_qp_fac.den, 1, 1000); - RANGE_CHECK(cfg, rd_mult_arf_qp_fac.den, 1, 1000); - RANGE_CHECK(cfg, rd_mult_key_qp_fac.den, 1, 1000); - return VPX_CODEC_OK; }