Move the allocation of mi buffers to encode stage
The mbmi buffers are used to store mode information at block level.
In allintra encode though minimum partition sf setting can be 8x8,
these buffers were allocated at init time by assuming minimum
partition size as 4x4.
As the minimum partition size is known in the encode stage, this CL
moves the allocation of mi buffers from init stage to encode stage
and the buffers are allocated based on minimum partition size.
For AVIF still-image encode with speed = 9,
HEAP Memory reduction(%)
Resolution threads=1 threads=4
640x360 19.96 15.78
768x512 19.14 15.54
832x480 23.59 20.20
1280x720 24.15 21.50
For threads=4, an average encode time reduction of ~13.75% is
observed for 360p-720p resolutions.
HEAP memory reduction was measured using the following command.
$valgrind --tool=massif ./avifenc ...
Change-Id: I2cfb2a594a6bc3a7f748910a05d88d2f7316f336
diff --git a/av1/common/alloccommon.c b/av1/common/alloccommon.c
index d2e01ea..9364b09 100644
--- a/av1/common/alloccommon.c
+++ b/av1/common/alloccommon.c
@@ -476,15 +476,16 @@
return 0;
}
-int av1_alloc_context_buffers(AV1_COMMON *cm, int width, int height, int mode) {
+int av1_alloc_context_buffers(AV1_COMMON *cm, int width, int height, int mode,
+ BLOCK_SIZE min_partition_size) {
CommonModeInfoParams *const mi_params = &cm->mi_params;
- mi_params->set_mb_mi(mi_params, width, height, mode);
+ mi_params->set_mb_mi(mi_params, width, height, mode, min_partition_size);
if (alloc_mi(mi_params)) goto fail;
return 0;
fail:
// clear the mi_* values to force a realloc on resync
- mi_params->set_mb_mi(mi_params, 0, 0, 0);
+ mi_params->set_mb_mi(mi_params, 0, 0, 0, BLOCK_4X4);
av1_free_context_buffers(cm);
return 1;
}
diff --git a/av1/common/alloccommon.h b/av1/common/alloccommon.h
index fbfe639..ced93b6 100644
--- a/av1/common/alloccommon.h
+++ b/av1/common/alloccommon.h
@@ -16,6 +16,8 @@
#include "config/aom_config.h"
+#include "av1/common/enums.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -34,7 +36,7 @@
int num_planes);
void av1_free_above_context_buffers(struct CommonContexts *above_contexts);
int av1_alloc_context_buffers(struct AV1Common *cm, int width, int height,
- int mode);
+ int mode, BLOCK_SIZE min_partition_size);
void av1_init_mi_buffers(struct CommonModeInfoParams *mi_params);
void av1_free_context_buffers(struct AV1Common *cm);
diff --git a/av1/common/av1_common_int.h b/av1/common/av1_common_int.h
index 6c3422d..e20e0c7 100644
--- a/av1/common/av1_common_int.h
+++ b/av1/common/av1_common_int.h
@@ -594,13 +594,16 @@
void (*setup_mi)(struct CommonModeInfoParams *mi_params);
/*!
* Allocate required memory for arrays in 'mi_params'.
- * \param[in,out] mi_params object containing common mode info parameters
- * \param width frame width
- * \param height frame height
- * \param mode encoding mode
+ * \param[in,out] mi_params object containing common mode info
+ * parameters
+ * \param width frame width
+ * \param height frame height
+ * \param mode encoding mode
+ * \param min_partition_size minimum partition size allowed while
+ * encoding
*/
void (*set_mb_mi)(struct CommonModeInfoParams *mi_params, int width,
- int height, int mode);
+ int height, int mode, BLOCK_SIZE min_partition_size);
/**@}*/
};
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 0341a7e..7e17c25 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -1901,7 +1901,7 @@
// dimensions as well as the overall size.
if (new_mi_cols > cm->mi_params.mi_cols ||
new_mi_rows > cm->mi_params.mi_rows) {
- if (av1_alloc_context_buffers(cm, width, height, 0)) {
+ if (av1_alloc_context_buffers(cm, width, height, 0, BLOCK_4X4)) {
// The cm->mi_* values have been cleared and any existing context
// buffers have been freed. Clear cm->width and cm->height to be
// consistent and to force a realloc next time.
@@ -1911,7 +1911,7 @@
"Failed to allocate context buffers");
}
} else {
- cm->mi_params.set_mb_mi(&cm->mi_params, width, height, 0);
+ cm->mi_params.set_mb_mi(&cm->mi_params, width, height, 0, BLOCK_4X4);
}
av1_init_mi_buffers(&cm->mi_params);
cm->width = width;
diff --git a/av1/decoder/decoder.c b/av1/decoder/decoder.c
index ca7b7e2..766a524 100644
--- a/av1/decoder/decoder.c
+++ b/av1/decoder/decoder.c
@@ -45,8 +45,9 @@
}
static void dec_set_mb_mi(CommonModeInfoParams *mi_params, int width,
- int height, int mode) {
+ int height, int mode, BLOCK_SIZE min_partition_size) {
(void)mode;
+ (void)min_partition_size;
// Ensure that the decoded width and height are both multiples of
// 8 luma pixels (note: this may only be a multiple of 4 chroma pixels if
// subsampling is used).
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 412cd2e..a01bad6 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -28,6 +28,7 @@
#include "av1/encoder/encoder.h"
#include "av1/encoder/encode_strategy.h"
#include "av1/encoder/encodeframe.h"
+#include "av1/encoder/encoder_alloc.h"
#include "av1/encoder/firstpass.h"
#include "av1/encoder/gop_structure.h"
#include "av1/encoder/pass2_strategy.h"
@@ -1552,6 +1553,9 @@
AOMMIN(gf_cfg->gf_min_pyr_height, gf_cfg->gf_max_pyr_height);
}
+ // Allocation of mi buffers.
+ alloc_mb_mode_info_buffers(cpi);
+
cpi->skip_tpl_setup_stats = 0;
#if !CONFIG_REALTIME_ONLY
cpi->twopass_frame.this_frame = NULL;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 4ae7747..d9116ad 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -296,11 +296,10 @@
AV1_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
- // We need to reallocate the context buffers here in case we need more mis.
- if (av1_alloc_context_buffers(cm, cm->width, cm->height, cpi->oxcf.mode)) {
- aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
- "Failed to allocate context buffers");
- }
+ // Setup mi_params here in case we need more mi's.
+ CommonModeInfoParams *const mi_params = &cm->mi_params;
+ mi_params->set_mb_mi(mi_params, cm->width, cm->height, cpi->oxcf.mode,
+ cpi->sf.part_sf.default_min_partition_size);
av1_init_macroblockd(cm, xd);
@@ -1162,7 +1161,7 @@
// width and height of the frame.
CommonModeInfoParams mi_params;
enc_set_mb_mi(&mi_params, oxcf->frm_dim_cfg.width, oxcf->frm_dim_cfg.height,
- oxcf->mode);
+ oxcf->mode, BLOCK_4X4);
const int bsize = BLOCK_16X16;
const int w = mi_size_wide[bsize];
@@ -2022,10 +2021,12 @@
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;
}
+ alloc_mb_mode_info_buffers(cpi);
av1_update_frame_size(cpi);
return 0;
diff --git a/av1/encoder/encoder_alloc.h b/av1/encoder/encoder_alloc.h
index 8298780..6dee2b2 100644
--- a/av1/encoder/encoder_alloc.h
+++ b/av1/encoder/encoder_alloc.h
@@ -56,11 +56,11 @@
static AOM_INLINE void alloc_compressor_data(AV1_COMP *cpi) {
AV1_COMMON *cm = &cpi->common;
+ CommonModeInfoParams *const mi_params = &cm->mi_params;
- if (av1_alloc_context_buffers(cm, cm->width, cm->height, cpi->oxcf.mode)) {
- aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
- "Failed to allocate context buffers");
- }
+ // Setup mi_params
+ mi_params->set_mb_mi(mi_params, cm->width, cm->height, cpi->oxcf.mode,
+ cpi->sf.part_sf.default_min_partition_size);
if (!is_stat_generation_stage(cpi)) {
av1_alloc_txb_buf(cpi);
@@ -92,6 +92,17 @@
av1_alloc_pmc(cpi, BLOCK_16X16, &cpi->td.shared_coeff_buf);
}
+// Allocate mbmi buffers which are used to store mode information at block
+// level.
+static AOM_INLINE void alloc_mb_mode_info_buffers(AV1_COMP *const cpi) {
+ AV1_COMMON *const cm = &cpi->common;
+ if (av1_alloc_context_buffers(cm, cm->width, cm->height, cpi->oxcf.mode,
+ cpi->sf.part_sf.default_min_partition_size)) {
+ aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate context buffers");
+ }
+}
+
static AOM_INLINE void realloc_segmentation_maps(AV1_COMP *cpi) {
AV1_COMMON *const cm = &cpi->common;
CommonModeInfoParams *const mi_params = &cm->mi_params;
diff --git a/av1/encoder/encoder_utils.h b/av1/encoder/encoder_utils.h
index 34a2b6d..d5975dd 100644
--- a/av1/encoder/encoder_utils.h
+++ b/av1/encoder/encoder_utils.h
@@ -86,18 +86,21 @@
}
static AOM_INLINE void enc_set_mb_mi(CommonModeInfoParams *mi_params, int width,
- int height, int mode) {
+ int height, int mode,
+ BLOCK_SIZE min_partition_size) {
const int is_4k_or_larger = AOMMIN(width, height) >= 2160;
const int is_realtime_mode = (mode == REALTIME);
mi_params->mi_alloc_bsize =
- (is_4k_or_larger || is_realtime_mode) ? BLOCK_8X8 : BLOCK_4X4;
+ (is_4k_or_larger || is_realtime_mode) ? BLOCK_8X8 : min_partition_size;
set_mb_mi(mi_params, width, height);
}
static AOM_INLINE void stat_stage_set_mb_mi(CommonModeInfoParams *mi_params,
- int width, int height, int mode) {
+ int width, int height, int mode,
+ BLOCK_SIZE min_partition_size) {
(void)mode;
+ (void)min_partition_size;
mi_params->mi_alloc_bsize = BLOCK_16X16;
set_mb_mi(mi_params, width, height);
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c
index 81cf06f..fbc2b56 100644
--- a/av1/encoder/svc_layercontext.c
+++ b/av1/encoder/svc_layercontext.c
@@ -11,6 +11,7 @@
#include <math.h>
#include "av1/encoder/encoder.h"
+#include "av1/encoder/encoder_alloc.h"
static void swap_ptr(void *a, void *b) {
void **a_p = (void **)a;
@@ -335,6 +336,7 @@
cpi->common.width = width;
cpi->common.height = height;
+ alloc_mb_mode_info_buffers(cpi);
av1_update_frame_size(cpi);
if (svc->spatial_layer_id == 0) svc->high_source_sad_superframe = 0;
}