diff --git a/av2/encoder/encoder.c b/av2/encoder/encoder.c index 1ce3a54a17..d6b3723987 100644 --- a/av2/encoder/encoder.c +++ b/av2/encoder/encoder.c @@ -2011,6 +2011,8 @@ void av2_remove_compressor(AV2_COMP *cpi) { free_bru_info(cm); + av2_ccso_ctx_free(cpi); + av2_remove_common(cm); av2_free_ref_frame_buffers(cm->buffer_pool); @@ -3048,9 +3050,16 @@ static void cdef_restoration_frame(AV2_COMP *cpi, AV2_COMMON *cm, const int ccso_height = xd->plane[AVM_PLANE_Y].dst.height; const int ccso_stride_ext = ccso_stride + (CCSO_PADDING_SIZE << 1); const int ccso_height_ext = ccso_height + (CCSO_PADDING_SIZE << 1); - CHECK_MEM_ERROR( - cm, ext_rec_y, - avm_malloc(sizeof(*ext_rec_y) * ccso_stride_ext * ccso_height_ext)); + const size_t ext_rec_y_size = (size_t)ccso_stride_ext * ccso_height_ext; + if (ext_rec_y_size > cpi->ccso_ext_rec_y_size) { + cpi->ccso_ext_rec_y_size = 0; + avm_free(cpi->ccso_ext_rec_y); + CHECK_MEM_ERROR( + cm, cpi->ccso_ext_rec_y, + avm_malloc(sizeof(*cpi->ccso_ext_rec_y) * ext_rec_y_size)); + cpi->ccso_ext_rec_y_size = ext_rec_y_size; + } + ext_rec_y = cpi->ccso_ext_rec_y; const int pic_height = cm->cur_frame->buf.y_height; const int pic_width = cm->cur_frame->buf.y_width; @@ -3117,23 +3126,28 @@ static void cdef_restoration_frame(AV2_COMP *cpi, AV2_COMMON *cm, av2_setup_dst_planes(xd->plane, &cm->cur_frame->buf, 0, 0, 0, num_planes, NULL); - uint16_t *rec_uv[CCSO_NUM_COMPONENTS]; - uint16_t *org_uv[CCSO_NUM_COMPONENTS]; const int ccso_stride = xd->plane[AVM_PLANE_Y].dst.width; - const int ccso_height = xd->plane[AVM_PLANE_Y].dst.height; for (int plane = AVM_PLANE_Y; plane < num_planes; ++plane) { - CHECK_MEM_ERROR( - cm, rec_uv[plane], - avm_malloc(sizeof(*rec_uv[plane]) * ccso_height * ccso_stride)); - CHECK_MEM_ERROR( - cm, org_uv[plane], - avm_malloc(sizeof(*org_uv[plane]) * ccso_height * ccso_stride)); + const size_t plane_size = + (size_t)xd->plane[plane].dst.height * ccso_stride; + if (plane_size > cpi->ccso_uv_size[plane]) { + cpi->ccso_uv_size[plane] = 0; + avm_free(cpi->ccso_rec_uv[plane]); + CHECK_MEM_ERROR( + cm, cpi->ccso_rec_uv[plane], + avm_malloc(sizeof(*cpi->ccso_rec_uv[plane]) * plane_size)); + avm_free(cpi->ccso_org_uv[plane]); + CHECK_MEM_ERROR( + cm, cpi->ccso_org_uv[plane], + avm_malloc(sizeof(*cpi->ccso_org_uv[plane]) * plane_size)); + cpi->ccso_uv_size[plane] = plane_size; + } - // Reading original and reconstructed chroma samples as input + // Copy original and reconstructed samples for this plane. const YV12_BUFFER_CONFIG *src = cpi->source; uint16_t *rec_buffer = xd->plane[plane].dst.buf; - uint16_t *src_cpy = org_uv[plane]; - uint16_t *rec_cpy = rec_uv[plane]; + uint16_t *src_cpy = cpi->ccso_org_uv[plane]; + uint16_t *rec_cpy = cpi->ccso_rec_uv[plane]; const int pic_height = xd->plane[plane].dst.height; const int pic_width = xd->plane[plane].dst.width; const int rec_stride = xd->plane[plane].dst.stride; @@ -3151,24 +3165,19 @@ static void cdef_restoration_frame(AV2_COMP *cpi, AV2_COMMON *cm, src_cpy += ccso_stride; } } - av2_ccso_search(cm, xd, cpi->td.mb.rdmult, ext_rec_y, rec_uv, org_uv, - cpi->error_resilient_frame_seen + av2_ccso_search(cm, xd, cpi->td.mb.rdmult, ext_rec_y, cpi->ccso_rec_uv, + cpi->ccso_org_uv, cpi->error_resilient_frame_seen #if CONFIG_ENTROPY_STATS , &cpi->td #endif , cpi->sf.lpf_sf.early_terminate_ccso_search_by_cost, - cpi->sf.lpf_sf.ccso_chroma_dep); + cpi->sf.lpf_sf.ccso_chroma_dep, &cpi->ccso_ctx); ccso_frame(&cm->cur_frame->buf, cm, xd, ext_rec_y); #if CONFIG_MISMATCH_DEBUG mismatch_record_frame(&cm->cur_frame->buf, num_planes, 2); #endif - avm_free(ext_rec_y); - for (int plane = AVM_PLANE_Y; plane < num_planes; ++plane) { - avm_free(rec_uv[plane]); - avm_free(org_uv[plane]); - } } if (use_gdf) { diff --git a/av2/encoder/encoder.h b/av2/encoder/encoder.h index c53fe5deba..caf20a5e69 100644 --- a/av2/encoder/encoder.h +++ b/av2/encoder/encoder.h @@ -49,6 +49,7 @@ #include "av2/encoder/speed_features.h" #include "av2/encoder/tokenize.h" #include "av2/encoder/tpl_model.h" +#include "av2/encoder/pickccso.h" #include "av2/encoder/av2_noise_estimate.h" #include "av2/common/banding_metadata.h" @@ -3133,6 +3134,32 @@ typedef struct AV2_COMP { * Flag indicating if banding metadata is available for the current frame */ int band_metadata_present; + + /*! + * CCSO search context holding persistent buffers (allocated on first use, + * freed at encoder close). + */ + CcsoCtx ccso_ctx; + /*! + * Extended luma reconstruction buffer for CCSO search. + */ + uint16_t *ccso_ext_rec_y; + /*! + * Allocated size of ccso_ext_rec_y in elements. + */ + size_t ccso_ext_rec_y_size; + /*! + * Per-plane chroma reconstruction buffers for CCSO search. + */ + uint16_t *ccso_rec_uv[CCSO_NUM_COMPONENTS]; + /*! + * Per-plane chroma original sample buffers for CCSO search. + */ + uint16_t *ccso_org_uv[CCSO_NUM_COMPONENTS]; + /*! + * Allocated sizes of ccso_rec_uv / ccso_org_uv in elements. + */ + size_t ccso_uv_size[CCSO_NUM_COMPONENTS]; } AV2_COMP; /*! diff --git a/av2/encoder/pickccso.c b/av2/encoder/pickccso.c index c5a6fe44e7..3e7dc77317 100644 --- a/av2/encoder/pickccso.c +++ b/av2/encoder/pickccso.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -25,56 +26,6 @@ #include "av2/encoder/encoder.h" #include "av2/encoder/pickccso.h" -typedef struct { - uint8_t final_band_log2; - int8_t best_filter_offset[CCSO_BAND_NUM * 16]; - int8_t final_filter_offset[CCSO_BAND_NUM * 16]; - bool best_filter_enabled; - bool final_filter_enabled; - uint8_t final_ext_filter_support; - int final_reuse_ccso; - int final_sb_reuse_ccso; - uint8_t final_scale_idx; - uint8_t final_quant_idx; - uint8_t final_ccso_bo_only; - - uint16_t *temp_rec_uv_buf; - uint8_t *src_cls0; - uint8_t *src_cls1; - int chroma_error[CCSO_BAND_NUM * 16]; - int chroma_count[CCSO_BAND_NUM * 16]; - int *total_class_err[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL][CCSO_BAND_NUM]; - int *total_class_cnt[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL][CCSO_BAND_NUM]; - int *total_class_err_bo[CCSO_BAND_NUM]; - int *total_class_cnt_bo[CCSO_BAND_NUM]; - int ccso_stride; - int ccso_stride_ext; - bool *filter_control; - bool *best_filter_control; - bool *final_filter_control; - uint64_t unfiltered_dist_frame; - uint64_t filtered_dist_frame; - uint64_t *unfiltered_dist_block; - uint64_t *training_dist_block; - int *reuse_total_class_err[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL] - [CCSO_BAND_NUM]; - int *reuse_total_class_cnt[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL] - [CCSO_BAND_NUM]; - - // Single backing allocations of arrays above. - int *class_err_slab; // backs total_class_err - int *class_cnt_slab; // backs total_class_cnt - int *class_err_bo_slab; // backs total_class_err - int *class_cnt_bo_slab; // backs total_class_cnt - int *reuse_class_err_slab; // backs reuse_total_class_err - int *reuse_class_cnt_slab; // backs reuse_total_class_cnt -} CcsoCtx; - -// Number of (d0, d1, band) combinations spanned by total_class_err/cnt and -// reuse_total_class_err/cnt. -#define CCSO_CLASS_STATS_ENTRIES \ - (CCSO_INPUT_INTERVAL * CCSO_INPUT_INTERVAL * CCSO_BAND_NUM) - const int ccso_offset[8] = { -10, -7, -3, -1, 0, 1, 3, 7 }; const int ccso_scale[4] = { 1, 2, 3, 4 }; @@ -82,6 +33,12 @@ static INLINE bool reuse_ccso_class_info(const AV2_COMMON *cm) { return !(cm->bru.enabled); } +// Resets per-frame state in a persistent CcsoCtx while preserving all +// allocated buffer pointers and size-tracking fields. +static void ccso_ctx_reset(CcsoCtx *ctx) { + memset(ctx, 0, offsetof(CcsoCtx, class_err_slab)); +} + void ccso_derive_src_block_c(const uint16_t *src_y, uint8_t *const src_cls0, uint8_t *const src_cls1, const int src_y_stride, const int src_cls_stride, const int x, const int y, @@ -1100,21 +1057,94 @@ static void derive_lut_offset(int8_t *temp_filter_offset, int scale_idx, // Allocates buffers required for ccso parameter rdo search static void ccso_alloc_search_buffers(AV2_COMMON *cm, MACROBLOCKD *xd, CcsoCtx *ctx, int sb_count) { - int *p; + const size_t luma_size = + (size_t)xd->plane[AVM_PLANE_Y].dst.height * ctx->ccso_stride; + + if (sb_count > ctx->alloc_sb_count) { + ctx->alloc_sb_count = 0; + avm_free(ctx->class_err_slab); + CHECK_MEM_ERROR(cm, ctx->class_err_slab, + avm_malloc(sizeof(*ctx->class_err_slab) * + CCSO_CLASS_STATS_ENTRIES * sb_count)); + + avm_free(ctx->class_cnt_slab); + CHECK_MEM_ERROR(cm, ctx->class_cnt_slab, + avm_malloc(sizeof(*ctx->class_cnt_slab) * + CCSO_CLASS_STATS_ENTRIES * sb_count)); + + avm_free(ctx->class_err_bo_slab); + CHECK_MEM_ERROR( + cm, ctx->class_err_bo_slab, + avm_malloc(sizeof(*ctx->class_err_bo_slab) * CCSO_BAND_NUM * sb_count)); + + avm_free(ctx->class_cnt_bo_slab); + CHECK_MEM_ERROR( + cm, ctx->class_cnt_bo_slab, + avm_malloc(sizeof(*ctx->class_cnt_bo_slab) * CCSO_BAND_NUM * sb_count)); + + avm_free(ctx->unfiltered_dist_block); + CHECK_MEM_ERROR(cm, ctx->unfiltered_dist_block, + avm_malloc(sb_count * sizeof(*ctx->unfiltered_dist_block))); + + avm_free(ctx->training_dist_block); + CHECK_MEM_ERROR(cm, ctx->training_dist_block, + avm_malloc(sb_count * sizeof(*ctx->training_dist_block))); - CHECK_MEM_ERROR(cm, ctx->class_err_slab, - avm_malloc(sizeof(*ctx->class_err_slab) * - CCSO_CLASS_STATS_ENTRIES * sb_count)); - p = ctx->class_err_slab; + avm_free(ctx->filter_control); + CHECK_MEM_ERROR(cm, ctx->filter_control, + avm_malloc(sb_count * sizeof(*ctx->filter_control))); + + avm_free(ctx->best_filter_control); + CHECK_MEM_ERROR(cm, ctx->best_filter_control, + avm_malloc(sb_count * sizeof(*ctx->best_filter_control))); + + avm_free(ctx->final_filter_control); + CHECK_MEM_ERROR(cm, ctx->final_filter_control, + avm_malloc(sb_count * sizeof(*ctx->final_filter_control))); + + ctx->alloc_sb_count = sb_count; + } + + if (reuse_ccso_class_info(cm) && sb_count > ctx->alloc_reuse_sb_count) { + ctx->alloc_reuse_sb_count = 0; + avm_free(ctx->reuse_class_err_slab); + CHECK_MEM_ERROR(cm, ctx->reuse_class_err_slab, + avm_malloc(sizeof(*ctx->reuse_class_err_slab) * + CCSO_CLASS_STATS_ENTRIES * sb_count)); + + avm_free(ctx->reuse_class_cnt_slab); + CHECK_MEM_ERROR(cm, ctx->reuse_class_cnt_slab, + avm_malloc(sizeof(*ctx->reuse_class_cnt_slab) * + CCSO_CLASS_STATS_ENTRIES * sb_count)); + + ctx->alloc_reuse_sb_count = sb_count; + } + + if (luma_size > ctx->alloc_luma_size) { + ctx->alloc_luma_size = 0; + avm_free(ctx->temp_rec_uv_buf); + CHECK_MEM_ERROR(cm, ctx->temp_rec_uv_buf, + avm_malloc(luma_size * sizeof(*ctx->temp_rec_uv_buf))); + + avm_free(ctx->src_cls0); + CHECK_MEM_ERROR(cm, ctx->src_cls0, + avm_malloc(luma_size * sizeof(*ctx->src_cls0))); + + avm_free(ctx->src_cls1); + CHECK_MEM_ERROR(cm, ctx->src_cls1, + avm_malloc(luma_size * sizeof(*ctx->src_cls1))); + + ctx->alloc_luma_size = luma_size; + } + + // Re-establish internal pointer layout (depends on current sb_count). + int *p = ctx->class_err_slab; for (int d0 = 0; d0 < CCSO_INPUT_INTERVAL; ++d0) for (int d1 = 0; d1 < CCSO_INPUT_INTERVAL; ++d1) for (int band_num = 0; band_num < CCSO_BAND_NUM; ++band_num, p += sb_count) ctx->total_class_err[d0][d1][band_num] = p; - CHECK_MEM_ERROR(cm, ctx->class_cnt_slab, - avm_malloc(sizeof(*ctx->class_cnt_slab) * - CCSO_CLASS_STATS_ENTRIES * sb_count)); p = ctx->class_cnt_slab; for (int d0 = 0; d0 < CCSO_INPUT_INTERVAL; ++d0) for (int d1 = 0; d1 < CCSO_INPUT_INTERVAL; ++d1) @@ -1122,24 +1152,15 @@ static void ccso_alloc_search_buffers(AV2_COMMON *cm, MACROBLOCKD *xd, ++band_num, p += sb_count) ctx->total_class_cnt[d0][d1][band_num] = p; - CHECK_MEM_ERROR( - cm, ctx->class_err_bo_slab, - avm_malloc(sizeof(*ctx->class_err_bo_slab) * CCSO_BAND_NUM * sb_count)); p = ctx->class_err_bo_slab; for (int band_num = 0; band_num < CCSO_BAND_NUM; ++band_num, p += sb_count) ctx->total_class_err_bo[band_num] = p; - CHECK_MEM_ERROR( - cm, ctx->class_cnt_bo_slab, - avm_malloc(sizeof(*ctx->class_cnt_bo_slab) * CCSO_BAND_NUM * sb_count)); p = ctx->class_cnt_bo_slab; for (int band_num = 0; band_num < CCSO_BAND_NUM; ++band_num, p += sb_count) ctx->total_class_cnt_bo[band_num] = p; if (reuse_ccso_class_info(cm)) { - CHECK_MEM_ERROR(cm, ctx->reuse_class_err_slab, - avm_malloc(sizeof(*ctx->reuse_class_err_slab) * - CCSO_CLASS_STATS_ENTRIES * sb_count)); p = ctx->reuse_class_err_slab; for (int d0 = 0; d0 < CCSO_INPUT_INTERVAL; ++d0) for (int d1 = 0; d1 < CCSO_INPUT_INTERVAL; ++d1) @@ -1147,9 +1168,6 @@ static void ccso_alloc_search_buffers(AV2_COMMON *cm, MACROBLOCKD *xd, ++band_num, p += sb_count) ctx->reuse_total_class_err[d0][d1][band_num] = p; - CHECK_MEM_ERROR(cm, ctx->reuse_class_cnt_slab, - avm_malloc(sizeof(*ctx->reuse_class_cnt_slab) * - CCSO_CLASS_STATS_ENTRIES * sb_count)); p = ctx->reuse_class_cnt_slab; for (int d0 = 0; d0 < CCSO_INPUT_INTERVAL; ++d0) for (int d1 = 0; d1 < CCSO_INPUT_INTERVAL; ++d1) @@ -1157,32 +1175,12 @@ static void ccso_alloc_search_buffers(AV2_COMMON *cm, MACROBLOCKD *xd, ++band_num, p += sb_count) ctx->reuse_total_class_cnt[d0][d1][band_num] = p; } - - CHECK_MEM_ERROR(cm, ctx->unfiltered_dist_block, - avm_malloc(sb_count * sizeof(*ctx->unfiltered_dist_block))); - CHECK_MEM_ERROR(cm, ctx->training_dist_block, - avm_malloc(sb_count * sizeof(*ctx->training_dist_block))); - - CHECK_MEM_ERROR(cm, ctx->filter_control, - avm_malloc(sb_count * sizeof(*ctx->filter_control))); - CHECK_MEM_ERROR(cm, ctx->best_filter_control, - avm_malloc(sb_count * sizeof(*ctx->best_filter_control))); - CHECK_MEM_ERROR(cm, ctx->final_filter_control, - avm_malloc(sb_count * sizeof(*ctx->final_filter_control))); - - CHECK_MEM_ERROR(cm, ctx->temp_rec_uv_buf, - avm_malloc(xd->plane[AVM_PLANE_Y].dst.height * - ctx->ccso_stride * sizeof(*ctx->temp_rec_uv_buf))); - CHECK_MEM_ERROR(cm, ctx->src_cls0, - avm_malloc(xd->plane[AVM_PLANE_Y].dst.height * - ctx->ccso_stride * sizeof(*ctx->src_cls0))); - CHECK_MEM_ERROR(cm, ctx->src_cls1, - avm_malloc(xd->plane[AVM_PLANE_Y].dst.height * - ctx->ccso_stride * sizeof(*ctx->src_cls1))); } -// Frees ccso rdo search buffers. -static void ccso_free_search_buffers(CcsoCtx *ctx) { +// Frees all persistent CCSO encoder buffers (pixel buffers + RDO scratch). +// Call once at encoder close via av2_remove_compressor. +void av2_ccso_ctx_free(AV2_COMP *cpi) { + CcsoCtx *ctx = &cpi->ccso_ctx; avm_free(ctx->class_err_slab); avm_free(ctx->class_cnt_slab); avm_free(ctx->class_err_bo_slab); @@ -1197,6 +1195,11 @@ static void ccso_free_search_buffers(CcsoCtx *ctx) { avm_free(ctx->temp_rec_uv_buf); avm_free(ctx->src_cls0); avm_free(ctx->src_cls1); + avm_free(cpi->ccso_ext_rec_y); + for (int plane = 0; plane < CCSO_NUM_COMPONENTS; ++plane) { + avm_free(cpi->ccso_rec_uv[plane]); + avm_free(cpi->ccso_org_uv[plane]); + } } // Writes val into the MB_MODE_INFO field that stores CCSO's per-block @@ -1550,7 +1553,8 @@ static void derive_ccso_filter(CcsoCtx *ctx, AV2_COMMON *cm, const int plane, } memcpy(ctx->temp_rec_uv_buf, rec_uv, sizeof(*ctx->temp_rec_uv_buf) * - xd->plane[0].dst.height * ctx->ccso_stride); + xd->plane[plane].dst.height * + ctx->ccso_stride); if (plane > 0) ccso_try_chroma_filter( ctx, cm, xd, plane, ext_rec_y, @@ -1814,7 +1818,6 @@ static void derive_ccso_filter(CcsoCtx *ctx, AV2_COMMON *cm, const int plane, ref_frame_ccso_info->reuse_root_ref[plane]; } } - ccso_free_search_buffers(ctx); } /* Derive the look-up table for a frame */ @@ -1827,7 +1830,8 @@ void av2_ccso_search(AV2_COMMON *cm, MACROBLOCKD *xd, int rdmult, ThreadData *td #endif , - int early_terminate_ccso_search, int ccso_chroma_dep) { + int early_terminate_ccso_search, int ccso_chroma_dep, + CcsoCtx *ctx) { const int num_planes = av2_num_planes(cm); const int rdmult_weight = clamp(cm->quant_params.base_qindex >> 3, 1, 37); int rdmult_orig = rdmult; @@ -1843,8 +1847,8 @@ void av2_ccso_search(AV2_COMMON *cm, MACROBLOCKD *xd, int rdmult, if ((int64_t)rdmult * rdmult_weight >= INT_MAX) { return; } else { - CcsoCtx *ctx; - CHECK_MEM_ERROR(cm, ctx, avm_calloc(1, sizeof(*ctx))); + ccso_ctx_reset(ctx); + av2_setup_dst_planes(xd->plane, &cm->cur_frame->buf, 0, 0, 0, num_planes, NULL); ctx->ccso_stride = xd->plane[AVM_PLANE_Y].dst.width; @@ -1877,6 +1881,5 @@ void av2_ccso_search(AV2_COMMON *cm, MACROBLOCKD *xd, int rdmult, early_terminate_ccso_search); cm->ccso_info.ccso_frame_flag |= cm->ccso_info.ccso_enable[0]; } - avm_free(ctx); } } diff --git a/av2/encoder/pickccso.h b/av2/encoder/pickccso.h index edc11e2b7e..6a223bb1b2 100644 --- a/av2/encoder/pickccso.h +++ b/av2/encoder/pickccso.h @@ -18,20 +18,81 @@ #include "av2/common/ccso.h" #include "av2/encoder/speed_features.h" +// Number of (d0, d1, band) combinations spanned by total_class_err/cnt. +#define CCSO_CLASS_STATS_ENTRIES \ + (CCSO_INPUT_INTERVAL * CCSO_INPUT_INTERVAL * CCSO_BAND_NUM) + +typedef struct { + // Per-frame state — zeroed at the start of each av2_ccso_search call. + uint8_t final_band_log2; + int8_t best_filter_offset[CCSO_BAND_NUM * 16]; + int8_t final_filter_offset[CCSO_BAND_NUM * 16]; + bool best_filter_enabled; + bool final_filter_enabled; + uint8_t final_ext_filter_support; + int final_reuse_ccso; + int final_sb_reuse_ccso; + uint8_t final_scale_idx; + uint8_t final_quant_idx; + uint8_t final_ccso_bo_only; + int chroma_error[CCSO_BAND_NUM * 16]; + int chroma_count[CCSO_BAND_NUM * 16]; + int *total_class_err[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL][CCSO_BAND_NUM]; + int *total_class_cnt[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL][CCSO_BAND_NUM]; + int *total_class_err_bo[CCSO_BAND_NUM]; + int *total_class_cnt_bo[CCSO_BAND_NUM]; + int ccso_stride; + int ccso_stride_ext; + uint64_t unfiltered_dist_frame; + uint64_t filtered_dist_frame; + int *reuse_total_class_err[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL] + [CCSO_BAND_NUM]; + int *reuse_total_class_cnt[CCSO_INPUT_INTERVAL][CCSO_INPUT_INTERVAL] + [CCSO_BAND_NUM]; + + // Persistent fields — survive across frames; ccso_ctx_reset zeros everything + // above this boundary via offsetof(CcsoCtx, class_err_slab). + // Adding a new allocated pointer: place it here and free it in + // av2_ccso_ctx_free. Adding a new per-frame field: place it above. + int *class_err_slab; // backs total_class_err + int *class_cnt_slab; // backs total_class_cnt + int *class_err_bo_slab; // backs total_class_err_bo + int *class_cnt_bo_slab; // backs total_class_cnt_bo + int *reuse_class_err_slab; // backs reuse_total_class_err + int *reuse_class_cnt_slab; // backs reuse_total_class_cnt + uint64_t *unfiltered_dist_block; + uint64_t *training_dist_block; + bool *filter_control; + bool *best_filter_control; + bool *final_filter_control; + uint16_t *temp_rec_uv_buf; + uint8_t *src_cls0; + uint8_t *src_cls1; + int alloc_sb_count; + int alloc_reuse_sb_count; + size_t alloc_luma_size; +} CcsoCtx; + #ifdef __cplusplus extern "C" { #endif +struct AV2_COMP; +struct ThreadData; + void av2_ccso_search(AV2_COMMON *cm, MACROBLOCKD *xd, int rdmult, const uint16_t *ext_rec_y, uint16_t *rec_uv[MAX_MB_PLANE], uint16_t *org_uv[MAX_MB_PLANE], bool error_resilient_frame_seen #if CONFIG_ENTROPY_STATS , - ThreadData *td + struct ThreadData *td #endif , - int early_terminate_ccso_search, int ccso_chroma_dep); + int early_terminate_ccso_search, int ccso_chroma_dep, + CcsoCtx *ctx); + +void av2_ccso_ctx_free(struct AV2_COMP *cpi); #ifdef __cplusplus } // extern "C"