Snap for 11383711 from 4c1c882d56675a5d82eef3de3b199ba0a41b6da1 to mainline-ipsec-release
Change-Id: I904877e16e32cf96c3f004d771e15a33220b6f58
diff --git a/AUTHORS b/AUTHORS
index ade7a1a..509c0d1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -235,6 +235,7 @@
Rostislav Pehlivanov <rpehlivanov@mozilla.com>
Ruiling Song <ruiling.song@intel.com>
Rui Ueyama <ruiu@google.com>
+Ruoyu Zhong <zhongruoyu@outlook.com>
Rupert Swarbrick <rupert.swarbrick@argondesign.com>
Ryan Lei <ryanlei@fb.com>
Ryan Overbeck <rover@google.com>
diff --git a/CHANGELOG b/CHANGELOG
index 9f0cabb..daa83a1 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,24 @@
+2024-01-17 v3.8.1
+ This release includes several bug fixes. This release is ABI
+ compatible with the last release. See
+ https://aomedia.googlesource.com/aom/+log/v3.8.0..v3.8.1 for all the
+ commits in this release.
+
+ - Bug Fixes
+ * aomedia:3520: get_cubic_kernel_dbl: Assertion `0 <= x && x < 1'
+ failed.
+ * aomedia:3526: alloc_compressor_data() is called during every
+ aom_codec_control() call on the encoder.
+ * aomedia:3527: aom/av1/encoder/mcomp.c:1810: av1_full_pixel_search:
+ Assertion `ms_params->ms_buffers.ref->width ==
+ ms_params->ms_buffers.src->width' failed.
+ * aomedia:3534: libaom encoder crashed by AOM_USAGE_ALL_INTRA and
+ AOM_EFLAG_NO_REF_LAST flags.
+ * b/310455204: Recreate workers if necessary.
+ * b/310548198: Update frame size in actual encoding.
+ * b/314858909: Do not use adaptive error estimate.
+ * Fix a hang of cmake on arm64 macOS with cmake 3.27.0 or later.
+
2023-11-30 v3.8.0
This release includes new codec interfaces, compression efficiency and
perceptual improvements, speedup and memory optimizations and many bug
@@ -70,7 +91,7 @@
* aomedia:3478: GCC 12.2.0 emits a -Wstringop-overflow warning on
aom/av1/encoder/motion_search_facade.c
* aomedia:3489: Detect encoder and image high bit depth mismatch
- * aomedia:3491: heap-buffer-overflow on frame size change
+ * aomedia:3491: heap-buffer-overflow on frame size change (CVE-2023-6879)
* b/303023614: Segfault at encoding time for high bit depth images
2023-08-10 v3.7.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c97ccd1..308a93d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,7 +59,7 @@
#
# We set SO_FILE_VERSION = [c-a].a.r
set(LT_CURRENT 11)
-set(LT_REVISION 0)
+set(LT_REVISION 1)
set(LT_AGE 8)
math(EXPR SO_VERSION "${LT_CURRENT} - ${LT_AGE}")
set(SO_FILE_VERSION "${SO_VERSION}.${LT_AGE}.${LT_REVISION}")
diff --git a/METADATA b/METADATA
index 54033f1..35df8b8 100644
--- a/METADATA
+++ b/METADATA
@@ -20,10 +20,10 @@
type: GIT
value: "https://aomedia.googlesource.com/aom/"
}
- version: "v3.8.0"
+ version: "v3.8.1"
last_upgrade_date {
- year: 2023
- month: 12
- day: 6
+ year: 2024
+ month: 1
+ day: 22
}
}
diff --git a/README.android b/README.android
index 09091d5..50860bf 100644
--- a/README.android
+++ b/README.android
@@ -1,12 +1,12 @@
Name: libaom
URL: https://aomedia.org
-Version: v3.8.0
+Version: v3.8.1
License: BSD
License File: libaom/LICENSE
-Date: Wednesday December 06 2023
-Branch: v3.8.0
-Commit: b681eac83963950afc7be55df56c22fa5210aaa2
+Date: Monday January 22 2024
+Branch: v3.8.1
+Commit: bb6430482199eaefbeaaa396600935082bc43f66
Description:
Contains the sources used to compile libaom.
diff --git a/README.version b/README.version
index c6bee0a..3b99200 100644
--- a/README.version
+++ b/README.version
@@ -1,3 +1,3 @@
URL: https://aomedia.googlesource.com/aom/
-Version: v3.8.0
+Version: v3.8.1
Local Modifications:
diff --git a/aom_dsp/flow_estimation/arm/disflow_neon.c b/aom_dsp/flow_estimation/arm/disflow_neon.c
index e2ba0e0..f091366 100644
--- a/aom_dsp/flow_estimation/arm/disflow_neon.c
+++ b/aom_dsp/flow_estimation/arm/disflow_neon.c
@@ -20,7 +20,14 @@
#include "config/aom_dsp_rtcd.h"
static INLINE void get_cubic_kernel_dbl(double x, double *kernel) {
- assert(0 <= x && x < 1);
+ // Check that the fractional position is in range.
+ //
+ // Note: x is calculated from (eg.) `u_frac = u - floor(u)`.
+ // Mathematically, this implies that 0 <= x < 1. However, in practice it is
+ // possible to have x == 1 due to floating point rounding. This is fine,
+ // and we still interpolate correctly if we allow x = 1.
+ assert(0 <= x && x <= 1);
+
double x2 = x * x;
double x3 = x2 * x;
kernel[0] = -0.5 * x + x2 - 0.5 * x3;
diff --git a/aom_dsp/flow_estimation/disflow.c b/aom_dsp/flow_estimation/disflow.c
index a010c81..ed5559c 100644
--- a/aom_dsp/flow_estimation/disflow.c
+++ b/aom_dsp/flow_estimation/disflow.c
@@ -53,7 +53,14 @@
#define UPSAMPLE_CENTER_OFFSET ((DOWNSAMPLE_FACTOR - 1) / 2)
static INLINE void get_cubic_kernel_dbl(double x, double *kernel) {
- assert(0 <= x && x < 1);
+ // Check that the fractional position is in range.
+ //
+ // Note: x is calculated from (eg.) `u_frac = u - floor(u)`.
+ // Mathematically, this implies that 0 <= x < 1. However, in practice it is
+ // possible to have x == 1 due to floating point rounding. This is fine,
+ // and we still interpolate correctly if we allow x = 1.
+ assert(0 <= x && x <= 1);
+
double x2 = x * x;
double x3 = x2 * x;
kernel[0] = -0.5 * x + x2 - 0.5 * x3;
diff --git a/aom_dsp/flow_estimation/x86/disflow_sse4.c b/aom_dsp/flow_estimation/x86/disflow_sse4.c
index 77784ee..3c2159a 100644
--- a/aom_dsp/flow_estimation/x86/disflow_sse4.c
+++ b/aom_dsp/flow_estimation/x86/disflow_sse4.c
@@ -28,7 +28,14 @@
// Note: Max sum(+ve coefficients) = 1.125 * scale
static INLINE void get_cubic_kernel_dbl(double x, double *kernel) {
- assert(0 <= x && x < 1);
+ // Check that the fractional position is in range.
+ //
+ // Note: x is calculated from (eg.) `u_frac = u - floor(u)`.
+ // Mathematically, this implies that 0 <= x < 1. However, in practice it is
+ // possible to have x == 1 due to floating point rounding. This is fine,
+ // and we still interpolate correctly if we allow x = 1.
+ assert(0 <= x && x <= 1);
+
double x2 = x * x;
double x3 = x2 * x;
kernel[0] = -0.5 * x + x2 - 0.5 * x3;
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 7256f48..1175a32 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -1499,20 +1499,27 @@
static aom_codec_err_t encoder_set_config(aom_codec_alg_priv_t *ctx,
const aom_codec_enc_cfg_t *cfg) {
- InitialDimensions *const initial_dimensions =
- &ctx->ppi->cpi->initial_dimensions;
aom_codec_err_t res;
int force_key = 0;
if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) {
if (cfg->g_lag_in_frames > 1 || cfg->g_pass != AOM_RC_ONE_PASS)
ERROR("Cannot change width or height after initialization");
- if (!valid_ref_frame_size(ctx->cfg.g_w, ctx->cfg.g_h, cfg->g_w, cfg->g_h) ||
- (initial_dimensions->width &&
- (int)cfg->g_w > initial_dimensions->width) ||
- (initial_dimensions->height &&
- (int)cfg->g_h > initial_dimensions->height))
+ // Note: function encoder_set_config() is allowed to be called multiple
+ // times. However, when the original frame width or height is less than two
+ // times of the new frame width or height, a forced key frame should be
+ // used. To make sure the correct detection of a forced key frame, we need
+ // to update the frame width and height only when the actual encoding is
+ // performed. cpi->last_coded_width and cpi->last_coded_height are used to
+ // track the actual coded frame size.
+ if (ctx->ppi->cpi->last_coded_width && ctx->ppi->cpi->last_coded_height &&
+ (!valid_ref_frame_size(ctx->ppi->cpi->last_coded_width,
+ ctx->ppi->cpi->last_coded_height, cfg->g_w,
+ cfg->g_h) ||
+ ((int)cfg->g_w > ctx->ppi->cpi->last_coded_width) ||
+ ((int)cfg->g_h > ctx->ppi->cpi->last_coded_height))) {
force_key = 1;
+ }
}
if (ctx->monochrome_on_init && cfg->monochrome == 0) {
@@ -2924,6 +2931,9 @@
AV1_COMP *cpi_lap = ppi->cpi_lap;
if (ppi->cpi == NULL) return AOM_CODEC_INVALID_PARAM;
+ ppi->cpi->last_coded_width = ppi->cpi->oxcf.frm_dim_cfg.width;
+ ppi->cpi->last_coded_height = ppi->cpi->oxcf.frm_dim_cfg.height;
+
if (ppi->lap_enabled && cpi_lap == NULL &&
ppi->cpi->oxcf.pass == AOM_RC_ONE_PASS)
return AOM_CODEC_INVALID_PARAM;
@@ -3123,12 +3133,25 @@
av1_compute_num_workers_for_mt(cpi);
num_workers = av1_get_max_num_workers(cpi);
}
- if ((num_workers > 1) && (ppi->p_mt_info.num_workers == 0)) {
+ if (num_workers > 1 && ppi->p_mt_info.num_workers < num_workers) {
// Obtain the maximum no. of frames that can be supported in a parallel
// encode set.
if (is_stat_consumption_stage(cpi)) {
ppi->num_fp_contexts = av1_compute_num_fp_contexts(ppi, &cpi->oxcf);
}
+ if (ppi->p_mt_info.num_workers > 0) {
+ av1_terminate_workers(ppi);
+ free_thread_data(ppi);
+ aom_free(ppi->p_mt_info.tile_thr_data);
+ ppi->p_mt_info.tile_thr_data = NULL;
+ aom_free(ppi->p_mt_info.workers);
+ ppi->p_mt_info.workers = NULL;
+ ppi->p_mt_info.num_workers = 0;
+ for (int j = 0; j < ppi->num_fp_contexts; j++) {
+ aom_free(ppi->parallel_cpi[j]->td.tctx);
+ ppi->parallel_cpi[j]->td.tctx = NULL;
+ }
+ }
av1_create_workers(ppi, num_workers);
av1_init_tile_thread_data(ppi, cpi->oxcf.pass == AOM_RC_FIRST_PASS);
}
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 6a4332c..07b6ffe 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -642,6 +642,12 @@
cm->height = oxcf->frm_dim_cfg.height;
cpi->is_dropped_frame = false;
+ InitialDimensions *const initial_dimensions = &cpi->initial_dimensions;
+ initial_dimensions->width = cm->width;
+ initial_dimensions->height = cm->height;
+
+ cpi->frame_size_related_setup_done = false;
+
alloc_compressor_data(cpi);
// Single thread case: use counts in common.
@@ -916,14 +922,14 @@
cpi->td.firstpass_ctx = NULL;
alloc_compressor_data(cpi);
realloc_segmentation_maps(cpi);
- initial_dimensions->width = initial_dimensions->height = 0;
+ initial_dimensions->width = cm->width;
+ initial_dimensions->height = cm->height;
+ cpi->frame_size_related_setup_done = false;
}
av1_update_frame_size(cpi);
rc->is_src_frame_alt_ref = 0;
- set_tile_info(cm, &cpi->oxcf.tile_cfg);
-
if (!cpi->ppi->rtc_ref.set_ref_frame_config)
cpi->ext_flags.refresh_frame.update_pending = 0;
cpi->ext_flags.refresh_frame_context_pending = 0;
@@ -1614,17 +1620,6 @@
snprintf((H) + strlen(H), sizeof(H) - strlen(H), (T), (V))
#endif // CONFIG_INTERNAL_STATS
-// This function will change the state and free the mutex of corresponding
-// workers and terminate the object. The object can not be re-used unless a call
-// to reset() is made.
-static AOM_INLINE void terminate_worker_data(AV1_PRIMARY *ppi) {
- PrimaryMultiThreadInfo *const p_mt_info = &ppi->p_mt_info;
- for (int t = p_mt_info->num_workers - 1; t >= 0; --t) {
- AVxWorker *const worker = &p_mt_info->workers[t];
- aom_get_worker_interface()->end(worker);
- }
-}
-
void av1_remove_primary_compressor(AV1_PRIMARY *ppi) {
if (!ppi) return;
#if !CONFIG_REALTIME_ONLY
@@ -1652,11 +1647,14 @@
av1_tpl_dealloc(&tpl_data->tpl_mt_sync);
#endif
- terminate_worker_data(ppi);
+ av1_terminate_workers(ppi);
free_thread_data(ppi);
aom_free(ppi->p_mt_info.tile_thr_data);
+ ppi->p_mt_info.tile_thr_data = NULL;
aom_free(ppi->p_mt_info.workers);
+ ppi->p_mt_info.workers = NULL;
+ ppi->p_mt_info.num_workers = 0;
aom_free(ppi);
}
@@ -2071,13 +2069,15 @@
#endif
}
+// TODO(chengchen): consider renaming this function as it is necessary
+// for the encoder to setup critical parameters, and it does not
+// deal with initial width any longer.
void av1_check_initial_width(AV1_COMP *cpi, int use_highbitdepth,
int subsampling_x, int subsampling_y) {
AV1_COMMON *const cm = &cpi->common;
SequenceHeader *const seq_params = cm->seq_params;
- InitialDimensions *const initial_dimensions = &cpi->initial_dimensions;
- if (!initial_dimensions->width ||
+ if (!cpi->frame_size_related_setup_done ||
seq_params->use_highbitdepth != use_highbitdepth ||
seq_params->subsampling_x != subsampling_x ||
seq_params->subsampling_y != subsampling_y) {
@@ -2097,9 +2097,8 @@
init_motion_estimation(cpi); // TODO(agrange) This can be removed.
- initial_dimensions->width = cm->width;
- initial_dimensions->height = cm->height;
cpi->initial_mbs = cm->mi_params.MBs;
+ cpi->frame_size_related_setup_done = true;
}
}
@@ -2136,18 +2135,18 @@
setup_denoiser_buffer(cpi);
#endif
- if (initial_dimensions->width && initial_dimensions->height &&
- (cm->width > initial_dimensions->width ||
- cm->height > initial_dimensions->height)) {
+ if (cm->width > initial_dimensions->width ||
+ cm->height > initial_dimensions->height) {
av1_free_context_buffers(cm);
av1_free_shared_coeff_buffer(&cpi->td.shared_coeff_buf);
av1_free_sms_tree(&cpi->td);
av1_free_pmc(cpi->td.firstpass_ctx, av1_num_planes(cm));
cpi->td.firstpass_ctx = NULL;
- alloc_mb_mode_info_buffers(cpi);
alloc_compressor_data(cpi);
realloc_segmentation_maps(cpi);
- initial_dimensions->width = initial_dimensions->height = 0;
+ initial_dimensions->width = cm->width;
+ initial_dimensions->height = cm->height;
+ cpi->frame_size_related_setup_done = false;
}
alloc_mb_mode_info_buffers(cpi);
av1_update_frame_size(cpi);
@@ -2229,6 +2228,7 @@
init_motion_estimation(cpi);
+ int has_valid_ref_frame = 0;
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
if (buf != NULL) {
@@ -2236,9 +2236,15 @@
av1_setup_scale_factors_for_frame(sf, buf->buf.y_crop_width,
buf->buf.y_crop_height, cm->width,
cm->height);
+ has_valid_ref_frame |= av1_is_valid_scale(sf);
if (av1_is_scaled(sf)) aom_extend_frame_borders(&buf->buf, num_planes);
}
}
+ if (!frame_is_intra_only(cm) && !has_valid_ref_frame) {
+ aom_internal_error(
+ cm->error, AOM_CODEC_CORRUPT_FRAME,
+ "Can't find at least one reference frame with valid size");
+ }
av1_setup_scale_factors_for_frame(&cm->sf_identity, cm->width, cm->height,
cm->width, cm->height);
@@ -2582,14 +2588,18 @@
if (cpi->ref_frame_flags & av1_ref_frame_flag_list[GOLDEN_FRAME]) {
const YV12_BUFFER_CONFIG *const ref =
get_ref_frame_yv12_buf(cm, GOLDEN_FRAME);
- if (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height)
+ if (ref == NULL || ref->y_crop_width != cm->width ||
+ ref->y_crop_height != cm->height) {
cpi->ref_frame_flags ^= AOM_GOLD_FLAG;
+ }
}
if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME]) {
const YV12_BUFFER_CONFIG *const ref =
get_ref_frame_yv12_buf(cm, ALTREF_FRAME);
- if (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height)
+ if (ref == NULL || ref->y_crop_width != cm->width ||
+ ref->y_crop_height != cm->height) {
cpi->ref_frame_flags ^= AOM_ALT_FLAG;
+ }
}
}
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index adec789..0a8bcde 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -3163,7 +3163,9 @@
FRAME_INDEX_SET frame_index_set;
/*!
- * Structure to store the dimensions of current frame.
+ * Structure to store the cm->width and cm->height in the last call
+ * of alloc_compressor_data().
+ * TODO(chengchen): rename this variable or delete it.
*/
InitialDimensions initial_dimensions;
@@ -3176,6 +3178,24 @@
int initial_mbs;
/*!
+ * Flag to indicate whether the frame size inforamation has been
+ * setup and propagated to associated allocations.
+ */
+ bool frame_size_related_setup_done;
+
+ /*!
+ * The width of the frame that is lastly encoded.
+ * It is updated in the function "encoder_encode()".
+ */
+ int last_coded_width;
+
+ /*!
+ * The height of the frame that is lastly encoded.
+ * It is updated in the function "encoder_encode()".
+ */
+ int last_coded_height;
+
+ /*!
* Resize related parameters.
*/
ResizePendingParams resize_pending_params;
@@ -3582,6 +3602,8 @@
/*!
* SSE between the current frame and the reconstructed last frame
+ * It is only used for CBR mode.
+ * It is not used if the reference frame has a different frame size.
*/
uint64_t rec_sse;
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index b878797..c15e396 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -1067,6 +1067,7 @@
void av1_create_workers(AV1_PRIMARY *ppi, int num_workers) {
PrimaryMultiThreadInfo *const p_mt_info = &ppi->p_mt_info;
const AVxWorkerInterface *const winterface = aom_get_worker_interface();
+ assert(p_mt_info->num_workers == 0);
AOM_CHECK_MEM_ERROR(&ppi->error, p_mt_info->workers,
aom_malloc(num_workers * sizeof(*p_mt_info->workers)));
@@ -1098,6 +1099,17 @@
}
}
+// This function will change the state and free the mutex of corresponding
+// workers and terminate the object. The object can not be re-used unless a call
+// to reset() is made.
+void av1_terminate_workers(AV1_PRIMARY *ppi) {
+ PrimaryMultiThreadInfo *const p_mt_info = &ppi->p_mt_info;
+ for (int t = 0; t < p_mt_info->num_workers; ++t) {
+ AVxWorker *const worker = &p_mt_info->workers[t];
+ aom_get_worker_interface()->end(worker);
+ }
+}
+
// This function returns 1 if frame parallel encode is supported for
// the current configuration. Returns 0 otherwise.
static AOM_INLINE int is_fpmt_config(AV1_PRIMARY *ppi, AV1EncoderConfig *oxcf) {
diff --git a/av1/encoder/ethread.h b/av1/encoder/ethread.h
index 4f4c232..f3f8629 100644
--- a/av1/encoder/ethread.h
+++ b/av1/encoder/ethread.h
@@ -88,6 +88,8 @@
void av1_create_workers(AV1_PRIMARY *ppi, int num_workers);
+void av1_terminate_workers(AV1_PRIMARY *ppi);
+
void av1_init_frame_mt(AV1_PRIMARY *ppi, AV1_COMP *cpi);
void av1_init_cdef_worker(AV1_COMP *cpi);
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 7ddc3e3..3631113 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -252,9 +252,9 @@
// Refine the motion search range according to the frame dimension
// for first pass test.
-static int get_search_range(const InitialDimensions *initial_dimensions) {
+static int get_search_range(int width, int height) {
int sr = 0;
- const int dim = AOMMIN(initial_dimensions->width, initial_dimensions->height);
+ const int dim = AOMMIN(width, height);
while ((dim << sr) < MAX_FULL_PEL_VAL) ++sr;
return sr;
@@ -293,18 +293,19 @@
const MV *ref_mv,
FULLPEL_MV *best_mv,
int *best_motion_err) {
+ AV1_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd;
FULLPEL_MV start_mv = get_fullmv_from_mv(ref_mv);
int tmp_err;
const BLOCK_SIZE bsize = xd->mi[0]->bsize;
const int new_mv_mode_penalty = NEW_MV_MODE_PENALTY;
- const int sr = get_search_range(&cpi->initial_dimensions);
+ const int sr = get_search_range(cm->width, cm->height);
const int step_param = cpi->sf.fp_sf.reduce_mv_step_param + sr;
const search_site_config *first_pass_search_sites =
av1_get_first_pass_search_site_config(cpi, x, NSTEP);
const int fine_search_interval =
- cpi->is_screen_content_type && cpi->common.features.allow_intrabc;
+ cpi->is_screen_content_type && cm->features.allow_intrabc;
FULLPEL_MOTION_SEARCH_PARAMS ms_params;
av1_make_default_fullpel_ms_params(&ms_params, cpi, x, bsize, ref_mv,
start_mv, first_pass_search_sites, NSTEP,
diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c
index a8b0d10..2462f1b 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -1807,7 +1807,6 @@
}
assert(ms_params->ms_buffers.ref->stride == ms_params->search_sites->stride);
- assert(ms_params->ms_buffers.ref->width == ms_params->ms_buffers.src->width);
switch (search_method) {
case FAST_BIGDIA:
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 3641c8b..d85440d 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -999,10 +999,9 @@
GF_GROUP_STATS *gf_stats) {
RATE_CONTROL *const rc = &cpi->rc;
TWO_PASS *const twopass = &cpi->ppi->twopass;
- InitialDimensions *const initial_dimensions = &cpi->initial_dimensions;
+ AV1_COMMON *const cm = &cpi->common;
// Motion breakout threshold for loop below depends on image size.
- const double mv_ratio_accumulator_thresh =
- (initial_dimensions->height + initial_dimensions->width) / 4.0;
+ const double mv_ratio_accumulator_thresh = (cm->height + cm->width) / 4.0;
if (!flash_detected) {
// Break clause to detect very still sections after motion. For example,
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 83c5944..9062136 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -188,8 +188,7 @@
correction_factor >= MIN_BPB_FACTOR);
if (cpi->oxcf.rc_cfg.mode == AOM_CBR && frame_type != KEY_FRAME &&
- accurate_estimate) {
- assert(cpi->rec_sse != UINT64_MAX);
+ accurate_estimate && cpi->rec_sse != UINT64_MAX) {
const int mbs = cm->mi_params.MBs;
const double sse_sqrt =
(double)((int)sqrt((double)(cpi->rec_sse)) << BPER_MB_NORMBITS) /
@@ -2086,6 +2085,13 @@
// TODO(yunqing): support scaled reference frames.
if (cpi->scaled_ref_buf[LAST_FRAME - 1]) return;
+ for (int i = 0; i < 2; ++i) {
+ if (unscaled_src->widths[i] != yv12->widths[i] ||
+ unscaled_src->heights[i] != yv12->heights[i]) {
+ return;
+ }
+ }
+
const int num_mi_cols = cm->mi_params.mi_cols;
const int num_mi_rows = cm->mi_params.mi_rows;
const BLOCK_SIZE bsize = BLOCK_64X64;
diff --git a/build/cmake/aom_configure.cmake b/build/cmake/aom_configure.cmake
index 6c932e8..917e7ca 100644
--- a/build/cmake/aom_configure.cmake
+++ b/build/cmake/aom_configure.cmake
@@ -184,7 +184,9 @@
string(STRIP "${AOM_AS_FLAGS}" AOM_AS_FLAGS)
elseif(AOM_TARGET_CPU MATCHES "arm")
if(AOM_TARGET_SYSTEM STREQUAL "Darwin")
- set(CMAKE_ASM_COMPILER as)
+ if(NOT CMAKE_ASM_COMPILER)
+ set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
+ endif()
set(AOM_AS_FLAGS -arch ${AOM_TARGET_CPU} -isysroot ${CMAKE_OSX_SYSROOT})
elseif(AOM_TARGET_SYSTEM STREQUAL "Windows")
if(NOT CMAKE_ASM_COMPILER)
diff --git a/config/arm/config/aom_config.asm b/config/arm/config/aom_config.asm
index 0cdc0cf..5bacc30 100644
--- a/config/arm/config/aom_config.asm
+++ b/config/arm/config/aom_config.asm
@@ -1,5 +1,5 @@
;
-; Copyright (c) 2023, Alliance for Open Media. All rights reserved
+; Copyright (c) 2024, Alliance for Open Media. All rights reserved
;
; This source code is subject to the terms of the BSD 2 Clause License and
; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/arm/config/aom_config.c b/config/arm/config/aom_config.c
index 691e782..03251c9 100644
--- a/config/arm/config/aom_config.c
+++ b/config/arm/config/aom_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/arm/config/aom_config.h b/config/arm/config/aom_config.h
index f59dc31..0d089d5 100644
--- a/config/arm/config/aom_config.h
+++ b/config/arm/config/aom_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/arm64/config/aom_config.asm b/config/arm64/config/aom_config.asm
index 108fa0b..8d1117e 100644
--- a/config/arm64/config/aom_config.asm
+++ b/config/arm64/config/aom_config.asm
@@ -1,5 +1,5 @@
;
-; Copyright (c) 2023, Alliance for Open Media. All rights reserved
+; Copyright (c) 2024, Alliance for Open Media. All rights reserved
;
; This source code is subject to the terms of the BSD 2 Clause License and
; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/arm64/config/aom_config.c b/config/arm64/config/aom_config.c
index 17df4f5..c600ad2 100644
--- a/config/arm64/config/aom_config.c
+++ b/config/arm64/config/aom_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/arm64/config/aom_config.h b/config/arm64/config/aom_config.h
index d81df21..4782c89 100644
--- a/config/arm64/config/aom_config.h
+++ b/config/arm64/config/aom_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/config/aom_version.h b/config/config/aom_version.h
index 46d20c2..51e763c 100644
--- a/config/config/aom_version.h
+++ b/config/config/aom_version.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
@@ -11,9 +11,9 @@
#define VERSION_MAJOR 3
#define VERSION_MINOR 8
-#define VERSION_PATCH 0
-#define VERSION_EXTRA "292-gd854021ff4"
+#define VERSION_PATCH 1
+#define VERSION_EXTRA "324-gd0d0651f9b"
#define VERSION_PACKED \
((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "3.8.0-292-gd854021ff4"
-#define VERSION_STRING " 3.8.0-292-gd854021ff4"
+#define VERSION_STRING_NOSP "3.8.1-324-gd0d0651f9b"
+#define VERSION_STRING " 3.8.1-324-gd0d0651f9b"
diff --git a/config/riscv64/config/aom_config.asm b/config/riscv64/config/aom_config.asm
index d286d42..594d55d 100644
--- a/config/riscv64/config/aom_config.asm
+++ b/config/riscv64/config/aom_config.asm
@@ -1,5 +1,5 @@
;
-; Copyright (c) 2023, Alliance for Open Media. All rights reserved
+; Copyright (c) 2024, Alliance for Open Media. All rights reserved
;
; This source code is subject to the terms of the BSD 2 Clause License and
; the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/riscv64/config/aom_config.c b/config/riscv64/config/aom_config.c
index 07609ac..c785346 100644
--- a/config/riscv64/config/aom_config.c
+++ b/config/riscv64/config/aom_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/riscv64/config/aom_config.h b/config/riscv64/config/aom_config.h
index 7e99639..9c37899 100644
--- a/config/riscv64/config/aom_config.h
+++ b/config/riscv64/config/aom_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/x86/config/aom_config.c b/config/x86/config/aom_config.c
index f6f929d..46444fa 100644
--- a/config/x86/config/aom_config.c
+++ b/config/x86/config/aom_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/x86/config/aom_config.h b/config/x86/config/aom_config.h
index fa4223a..0edc5c5 100644
--- a/config/x86/config/aom_config.h
+++ b/config/x86/config/aom_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/x86_64/config/aom_config.c b/config/x86_64/config/aom_config.c
index 8a75212..ee37f5b 100644
--- a/config/x86_64/config/aom_config.c
+++ b/config/x86_64/config/aom_config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/config/x86_64/config/aom_config.h b/config/x86_64/config/aom_config.h
index ead2b02..765481e 100644
--- a/config/x86_64/config/aom_config.h
+++ b/config/x86_64/config/aom_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Alliance for Open Media. All rights reserved
+ * Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
diff --git a/libaom_blocklist.txt b/libaom_blocklist.txt
index 06a721b..02b8508 100644
--- a/libaom_blocklist.txt
+++ b/libaom_blocklist.txt
@@ -26,3 +26,5 @@
fun:highbd_10_variance_sse2
# libaom/av1/encoder/encodeframe_utils.c: indirect call to assembly code on x86/x86_64 platform
fun:fast_detect_non_zero_motion
+# libaom/av1/common/reconintra.c: indirect call to assembly code on x86/x86_64 platform
+fun:highbd_build_intra_predictors
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index 07b2fc8..9a447b5 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -9,6 +9,7 @@
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
+#include <cassert>
#include <cstdlib>
#include <cstring>
#include <tuple>
@@ -320,37 +321,20 @@
return image;
}
-// Run this test to reproduce the bug in fuzz test: ASSERT: cpi->rec_sse !=
-// UINT64_MAX in av1_rc_bits_per_mb.
-TEST(EncodeAPI, Buganizer310766628) {
+TEST(EncodeAPI, Buganizer310548198) {
aom_codec_iface_t *const iface = aom_codec_av1_cx();
aom_codec_enc_cfg_t cfg;
-
- struct Config {
- unsigned int thread;
- unsigned int width;
- unsigned int height;
- aom_rc_mode end_usage;
- };
-
- struct Config init_config = { 16, 759, 383, AOM_CBR };
const unsigned int usage = AOM_USAGE_REALTIME;
ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK);
-
- cfg.g_threads = init_config.thread;
- cfg.g_w = init_config.width;
- cfg.g_h = init_config.height;
- cfg.g_timebase.num = 1;
- cfg.g_timebase.den = 1000 * 1000; // microseconds
+ cfg.g_w = 1;
+ cfg.g_h = 444;
cfg.g_pass = AOM_RC_ONE_PASS;
cfg.g_lag_in_frames = 0;
- cfg.rc_end_usage = init_config.end_usage;
- cfg.rc_min_quantizer = 2;
- cfg.rc_max_quantizer = 58;
aom_codec_ctx_t enc;
- const int speed = 7;
ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+
+ const int speed = 6;
ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, speed), AOM_CODEC_OK);
const aom_enc_frame_flags_t flags = 0;
@@ -368,19 +352,18 @@
}
aom_img_free(image);
- struct Config encode_config = { 2, 759, 383, AOM_VBR };
-
- cfg.g_threads = encode_config.thread;
- cfg.g_w = encode_config.width;
- cfg.g_h = encode_config.height;
- cfg.rc_end_usage = encode_config.end_usage;
-
+ cfg.g_w = 1;
+ cfg.g_h = 254;
ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK)
<< aom_codec_error_detail(&enc);
- // Encode a frame. This will trigger the assertion failure.
+ cfg.g_w = 1;
+ cfg.g_h = 154;
+ ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK)
+ << aom_codec_error_detail(&enc);
+
+ // Encode a frame.
image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
- ASSERT_NE(image, nullptr);
ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
frame_index++;
iter = nullptr;
@@ -404,88 +387,173 @@
ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
}
-// Run this test to reproduce the bug in fuzz test: Float-cast-overflow in
-// av1_rc_bits_per_mb.
-TEST(EncodeAPI, Buganizer310457427) {
- aom_codec_iface_t *const iface = aom_codec_av1_cx();
- aom_codec_enc_cfg_t cfg;
+// Emulates the WebCodecs VideoEncoder interface.
+class AV1Encoder {
+ public:
+ explicit AV1Encoder(int speed) : speed_(speed) {}
+ ~AV1Encoder();
- struct Config {
- unsigned int thread;
- unsigned int width;
- unsigned int height;
- aom_rc_mode end_usage;
- };
+ void Configure(unsigned int threads, unsigned int width, unsigned int height,
+ aom_rc_mode end_usage, unsigned int usage);
+ void Encode(bool key_frame);
- struct Config init_config = { 12, 896, 1076, AOM_CBR };
- const unsigned int usage = AOM_USAGE_REALTIME;
- ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK);
+ private:
+ // Flushes the encoder. Should be called after all the Encode() calls.
+ void Flush();
- cfg.g_threads = init_config.thread;
- cfg.g_w = init_config.width;
- cfg.g_h = init_config.height;
- cfg.g_timebase.num = 1;
- cfg.g_timebase.den = 1000 * 1000; // microseconds
- cfg.g_pass = AOM_RC_ONE_PASS;
- cfg.g_lag_in_frames = 0;
- cfg.rc_end_usage = init_config.end_usage;
- cfg.rc_min_quantizer = 2;
- cfg.rc_max_quantizer = 58;
+ const int speed_;
+ bool initialized_ = false;
+ aom_codec_enc_cfg_t cfg_;
+ aom_codec_ctx_t enc_;
+ int frame_index_ = 0;
+};
- aom_codec_ctx_t enc;
- const int speed = 7;
- ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
- ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, speed), AOM_CODEC_OK);
+AV1Encoder::~AV1Encoder() {
+ if (initialized_) {
+ Flush();
+ EXPECT_EQ(aom_codec_destroy(&enc_), AOM_CODEC_OK);
+ }
+}
- struct Config encode_config = { 6, 609, 1076, AOM_VBR };
- cfg.g_threads = encode_config.thread;
- cfg.g_w = encode_config.width;
- cfg.g_h = encode_config.height;
- cfg.rc_end_usage = encode_config.end_usage;
+void AV1Encoder::Configure(unsigned int threads, unsigned int width,
+ unsigned int height, aom_rc_mode end_usage,
+ unsigned int usage) {
+ if (!initialized_) {
+ aom_codec_iface_t *const iface = aom_codec_av1_cx();
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg_, usage), AOM_CODEC_OK);
+ cfg_.g_threads = threads;
+ cfg_.g_w = width;
+ cfg_.g_h = height;
+ cfg_.g_forced_max_frame_width = cfg_.g_w;
+ cfg_.g_forced_max_frame_height = cfg_.g_h;
+ cfg_.g_timebase.num = 1;
+ cfg_.g_timebase.den = 1000 * 1000; // microseconds
+ cfg_.g_pass = AOM_RC_ONE_PASS;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.rc_end_usage = end_usage;
+ cfg_.rc_min_quantizer = 2;
+ cfg_.rc_max_quantizer = 58;
+ ASSERT_EQ(aom_codec_enc_init(&enc_, iface, &cfg_, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc_, AOME_SET_CPUUSED, speed_), AOM_CODEC_OK);
+ initialized_ = true;
+ return;
+ }
- ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK)
- << aom_codec_error_detail(&enc);
+ ASSERT_EQ(usage, cfg_.g_usage);
+ cfg_.g_threads = threads;
+ cfg_.g_w = width;
+ cfg_.g_h = height;
+ cfg_.rc_end_usage = end_usage;
+ ASSERT_EQ(aom_codec_enc_config_set(&enc_, &cfg_), AOM_CODEC_OK)
+ << aom_codec_error_detail(&enc_);
+}
- const aom_enc_frame_flags_t flags = 0;
- int frame_index = 0;
-
- // Encode a frame.
- aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+void AV1Encoder::Encode(bool key_frame) {
+ assert(initialized_);
+ // TODO(wtc): Support high bit depths and other YUV formats.
+ aom_image_t *const image =
+ CreateGrayImage(AOM_IMG_FMT_I420, cfg_.g_w, cfg_.g_h);
ASSERT_NE(image, nullptr);
- ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
- frame_index++;
+ const aom_enc_frame_flags_t flags = key_frame ? AOM_EFLAG_FORCE_KF : 0;
+ ASSERT_EQ(aom_codec_encode(&enc_, image, frame_index_, 1, flags),
+ AOM_CODEC_OK);
+ frame_index_++;
const aom_codec_cx_pkt_t *pkt;
aom_codec_iter_t iter = nullptr;
- while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ while ((pkt = aom_codec_get_cx_data(&enc_, &iter)) != nullptr) {
ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
+ if (key_frame) {
+ ASSERT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, AOM_FRAME_IS_KEY);
+ }
}
aom_img_free(image);
+}
- // Encode a frame. This will trigger the float-cast-overflow bug which was
- // caused by division by zero.
- image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
- ASSERT_NE(image, nullptr);
- ASSERT_EQ(aom_codec_encode(&enc, image, frame_index, 1, flags), AOM_CODEC_OK);
- frame_index++;
- iter = nullptr;
- while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
- ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
- }
- aom_img_free(image);
-
- // Flush the encoder.
+void AV1Encoder::Flush() {
bool got_data;
do {
- ASSERT_EQ(aom_codec_encode(&enc, nullptr, 0, 0, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_encode(&enc_, nullptr, 0, 0, 0), AOM_CODEC_OK);
got_data = false;
- iter = nullptr;
- while ((pkt = aom_codec_get_cx_data(&enc, &iter)) != nullptr) {
+ const aom_codec_cx_pkt_t *pkt;
+ aom_codec_iter_t iter = nullptr;
+ while ((pkt = aom_codec_get_cx_data(&enc_, &iter)) != nullptr) {
ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
got_data = true;
}
} while (got_data);
+}
- ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
+TEST(EncodeAPI, Buganizer314858909) {
+ AV1Encoder encoder(7);
+
+ encoder.Configure(6, 1582, 750, AOM_CBR, AOM_USAGE_REALTIME);
+
+ // Encode a frame.
+ encoder.Encode(false);
+
+ encoder.Configure(0, 1582, 23, AOM_CBR, AOM_USAGE_REALTIME);
+
+ // Encode a frame..
+ encoder.Encode(false);
+
+ encoder.Configure(16, 1542, 363, AOM_CBR, AOM_USAGE_REALTIME);
+
+ // Encode a frame..
+ encoder.Encode(false);
+}
+
+// Run this test to reproduce the bug in fuzz test: ASSERT: cpi->rec_sse !=
+// UINT64_MAX in av1_rc_bits_per_mb.
+TEST(EncodeAPI, Buganizer310766628) {
+ AV1Encoder encoder(7);
+
+ encoder.Configure(16, 759, 383, AOM_CBR, AOM_USAGE_REALTIME);
+
+ // Encode a frame.
+ encoder.Encode(false);
+
+ encoder.Configure(2, 759, 383, AOM_VBR, AOM_USAGE_REALTIME);
+
+ // Encode a frame. This will trigger the assertion failure.
+ encoder.Encode(false);
+}
+
+// This test covers a possible use case where the change of frame sizes and
+// thread numbers happens before and after the first frame coding.
+TEST(EncodeAPI, Buganizer310455204) {
+ AV1Encoder encoder(7);
+
+ encoder.Configure(0, 1915, 503, AOM_VBR, AOM_USAGE_REALTIME);
+
+ encoder.Configure(4, 1, 1, AOM_VBR, AOM_USAGE_REALTIME);
+
+ encoder.Configure(6, 559, 503, AOM_CBR, AOM_USAGE_REALTIME);
+
+ // Encode a frame.
+ encoder.Encode(false);
+
+ // Increase the number of threads.
+ encoder.Configure(16, 1915, 503, AOM_CBR, AOM_USAGE_REALTIME);
+
+ // Encode a frame.
+ encoder.Encode(false);
+}
+
+// Run this test to reproduce the bug in fuzz test: Float-cast-overflow in
+// av1_rc_bits_per_mb.
+TEST(EncodeAPI, Buganizer310457427) {
+ AV1Encoder encoder(7);
+
+ encoder.Configure(12, 896, 1076, AOM_CBR, AOM_USAGE_REALTIME);
+
+ encoder.Configure(6, 609, 1076, AOM_VBR, AOM_USAGE_REALTIME);
+
+ // Encode a frame.
+ encoder.Encode(false);
+
+ // Encode a frame. This will trigger the float-cast-overflow bug which was
+ // caused by division by zero.
+ encoder.Encode(false);
}
class EncodeAPIParameterized
@@ -586,6 +654,26 @@
cfg.kf_max_dist = 1;
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0));
}
-#endif
+
+// A test that reproduces bug aomedia:3534.
+TEST(EncodeAPI, AllIntraAndNoRefLast) {
+ aom_codec_iface_t *iface = aom_codec_av1_cx();
+ aom_codec_enc_cfg_t cfg;
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_ALL_INTRA),
+ AOM_CODEC_OK);
+
+ aom_codec_ctx_t enc;
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+
+ aom_image_t *image = CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+ ASSERT_NE(image, nullptr);
+
+ ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, AOM_EFLAG_NO_REF_LAST),
+ AOM_CODEC_OK);
+
+ aom_img_free(image);
+ ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
+}
+#endif // !CONFIG_REALTIME_ONLY
} // namespace