| /* | 
 |  * Copyright (c) 2022, Alliance for Open Media. All rights reserved | 
 |  * | 
 |  * This source code is subject to the terms of the BSD 3-Clause Clear License | 
 |  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear | 
 |  * License was not distributed with this source code in the LICENSE file, you | 
 |  * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  If the | 
 |  * Alliance for Open Media Patent License 1.0 was not distributed with this | 
 |  * source code in the PATENTS file, you can obtain it at | 
 |  * aomedia.org/license/patent-license/. | 
 |  */ | 
 |  | 
 | #include "av1/common/bru.h" | 
 | #include "av1/common/common_data.h" | 
 | #include "config/aom_config.h" | 
 | #include "config/aom_dsp_rtcd.h" | 
 | #include "config/av1_rtcd.h" | 
 | #include "av1/common/reconinter.h" | 
 | #include "av1/common/ccso.h" | 
 |  | 
 | /* clean up tx_skip array for support and inactive SBs */ | 
 | void bru_update_txk_skip_array(const AV1_COMMON *cm, int mi_row, int mi_col, | 
 |                                TREE_TYPE tree_type, | 
 |                                const CHROMA_REF_INFO *chroma_ref_info, | 
 |                                int plane, int blk_w, int blk_h) { | 
 |   (void)tree_type; | 
 |   (void)chroma_ref_info; | 
 |   if (mi_col + blk_w > cm->mi_params.mi_cols) | 
 |     blk_w = cm->mi_params.mi_cols - mi_col; | 
 |  | 
 |   if (mi_row + blk_h > cm->mi_params.mi_rows) | 
 |     blk_h = cm->mi_params.mi_rows - mi_row; | 
 |  | 
 |   blk_w = blk_w >> ((plane == 0) ? 0 : cm->seq_params.subsampling_x); | 
 |   blk_h = blk_h >> ((plane == 0) ? 0 : cm->seq_params.subsampling_y); | 
 |  | 
 |   int w = ((cm->width + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) | 
 |           << MAX_SB_SIZE_LOG2; | 
 |   w >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_x); | 
 |   const uint32_t stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2; | 
 |   const int cols = (blk_w << MI_SIZE_LOG2) >> MIN_TX_SIZE_LOG2; | 
 |   const int rows = (blk_h << MI_SIZE_LOG2) >> MIN_TX_SIZE_LOG2; | 
 |   int x = (mi_col << MI_SIZE_LOG2) >> | 
 |           ((plane == 0) ? 0 : cm->seq_params.subsampling_x); | 
 |   int y = (mi_row << MI_SIZE_LOG2) >> | 
 |           ((plane == 0) ? 0 : cm->seq_params.subsampling_y); | 
 |   x = x >> MIN_TX_SIZE_LOG2; | 
 |   y = y >> MIN_TX_SIZE_LOG2; | 
 |   for (int r = 0; r < rows; r++) { | 
 |     for (int c = 0; c < cols; c++) { | 
 |       const uint32_t idx = (y + r) * stride + x + c; | 
 |       assert(idx < cm->mi_params.tx_skip_buf_size[plane]); | 
 |       assert(stride == cm->mi_params.tx_skip_stride[plane]); | 
 |       cm->mi_params.tx_skip[plane][idx] = 1; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /* Set correct mbmi address for inactive and support SB since there is no chance | 
 |  * to set them in later stage  */ | 
 | BruActiveMode set_sb_mbmi_bru_mode(const AV1_COMMON *cm, MACROBLOCKD *const xd, | 
 |                                    const int mi_col, const int mi_row, | 
 |                                    const BLOCK_SIZE bsize, | 
 |                                    const BruActiveMode bru_sb_mode) { | 
 |   // only set very first mi | 
 |   // for inactive SB, other location on the mi_grid is invalid | 
 |   // for active SB, later set_offset will redo the address assignment | 
 |   if (cm->bru.enabled) { | 
 |     xd->mi_col = mi_col; | 
 |     xd->mi_row = mi_row; | 
 |     const int mi_grid_idx = get_mi_grid_idx(&cm->mi_params, mi_row, mi_col); | 
 |     const int mi_alloc_idx = get_alloc_mi_idx(&cm->mi_params, mi_row, mi_col); | 
 |     cm->mi_params.mi_grid_base[mi_grid_idx] = | 
 |         &cm->mi_params.mi_alloc[mi_alloc_idx]; | 
 |     xd->mi = cm->mi_params.mi_grid_base + mi_grid_idx; | 
 |     xd->mi[0]->sb_active_mode = bru_sb_mode; | 
 |     // if not active, propagate to all the mi in bsize | 
 |     // this function will also be used in decoder | 
 |     if (bru_sb_mode != BRU_ACTIVE_SB) { | 
 |       const int mi_h = mi_size_high[bsize]; | 
 |       const int mi_w = mi_size_wide[bsize]; | 
 |       MB_MODE_INFO *const mi_addr = xd->mi[0]; | 
 |       const int x_inside_boundary = | 
 |           AOMMIN(mi_w, cm->mi_params.mi_cols - mi_col); | 
 |       const int y_inside_boundary = | 
 |           AOMMIN(mi_h, cm->mi_params.mi_rows - mi_row); | 
 |       const int mis = cm->mi_params.mi_stride; | 
 |       for (int y = 0; y < y_inside_boundary; y++) { | 
 |         for (int x_idx = 0; x_idx < x_inside_boundary; x_idx++) { | 
 |           xd->mi[x_idx + y * mis] = mi_addr; | 
 |         } | 
 |       } | 
 |     } | 
 |     return bru_sb_mode; | 
 |   } | 
 |   return BRU_ACTIVE_SB; | 
 | } | 
 |  | 
 | /* Copy recon data from BRU ref to current frame buffer. This is only used for | 
 |  * BRU_SUPPORT_SB of BRU optimized decoder/encoder */ | 
 | void bru_copy_sb(const struct AV1Common *cm, const int mi_col, | 
 |                  const int mi_row) { | 
 |   if (cm->bru.update_ref_idx < 0) | 
 |     return;  // now ref_idx is the sole indicator of frame level bru | 
 |   const int sb_size = cm->seq_params.sb_size; | 
 |   const int w = mi_size_wide[sb_size]; | 
 |   const int h = mi_size_high[sb_size]; | 
 |   RefCntBuffer *const ref_buf = get_ref_frame_buf(cm, cm->bru.update_ref_idx); | 
 |   YV12_BUFFER_CONFIG *const ref_src = &ref_buf->buf; | 
 |   YV12_BUFFER_CONFIG *const rec_dst = &cm->cur_frame->buf; | 
 |   const int x_inside_boundary = AOMMIN(w, cm->mi_params.mi_cols - mi_col) | 
 |                                 << MI_SIZE_LOG2; | 
 |   const int y_inside_boundary = AOMMIN(h, cm->mi_params.mi_rows - mi_row) | 
 |                                 << MI_SIZE_LOG2; | 
 |   const int x = mi_col << MI_SIZE_LOG2; | 
 |   const int y = mi_row << MI_SIZE_LOG2; | 
 |   for (int i_plane = 0; i_plane < av1_num_planes(cm); ++i_plane) { | 
 |     uint16_t *rec_data = rec_dst->buffers[i_plane]; | 
 |     uint16_t *ref_data = ref_src->buffers[i_plane]; | 
 |     int rec_stride = i_plane > 0 ? rec_dst->uv_stride : rec_dst->y_stride; | 
 |     int ref_stride = i_plane > 0 ? ref_src->uv_stride : ref_src->y_stride; | 
 |     int subsample_x = i_plane > 0 ? ref_src->subsampling_x : 0; | 
 |     int subsample_y = i_plane > 0 ? ref_src->subsampling_y : 0; | 
 |     uint64_t rec_offset = scaled_buffer_offset( | 
 |         x >> subsample_x, y >> subsample_y, rec_stride, NULL); | 
 |     uint64_t ref_offset = scaled_buffer_offset( | 
 |         x >> subsample_x, y >> subsample_y, ref_stride, NULL); | 
 |     copy_tile(x_inside_boundary >> subsample_x, | 
 |               y_inside_boundary >> subsample_y, ref_data + ref_offset, | 
 |               ref_stride, rec_data + rec_offset, rec_stride); | 
 |   } | 
 |   if (cm->seq_params.order_hint_info.enable_ref_frame_mvs) { | 
 |     // set cur_frame mvs to 0 | 
 |     bru_zero_sb_mvs(cm, -1, mi_row, mi_col, x_inside_boundary >> MI_SIZE_LOG2, | 
 |                     y_inside_boundary >> MI_SIZE_LOG2); | 
 |   } | 
 |   return; | 
 | } | 
 |  | 
 | /* Update recon data from current frame buffer to BRU ref. This is only used for | 
 |  * BRU_ACTIVE_SB of BRU optimized decoder/encoder */ | 
 | void bru_update_sb(const struct AV1Common *cm, const int mi_col, | 
 |                    const int mi_row) { | 
 |   if (cm->bru.update_ref_idx < 0) | 
 |     return;  // now ref_idx is the sole indicator of frame level bru | 
 |   RefCntBuffer *const ref_buf = get_ref_frame_buf(cm, cm->bru.update_ref_idx); | 
 |   // just swap these two | 
 |   YV12_BUFFER_CONFIG *const rec_dst = &ref_buf->buf; | 
 |   YV12_BUFFER_CONFIG *const ref_src = &cm->cur_frame->buf; | 
 |   const int sb_size = cm->seq_params.sb_size; | 
 |   const int w = mi_size_wide[sb_size]; | 
 |   const int h = mi_size_high[sb_size]; | 
 |   const int x_inside_boundary = AOMMIN(w, cm->mi_params.mi_cols - mi_col) | 
 |                                 << MI_SIZE_LOG2; | 
 |   const int y_inside_boundary = AOMMIN(h, cm->mi_params.mi_rows - mi_row) | 
 |                                 << MI_SIZE_LOG2; | 
 |   const int x = mi_col << MI_SIZE_LOG2; | 
 |   const int y = mi_row << MI_SIZE_LOG2; | 
 |  | 
 |   for (int i_plane = 0; i_plane < av1_num_planes(cm); ++i_plane) { | 
 |     uint16_t *rec_data = rec_dst->buffers[i_plane]; | 
 |     uint16_t *ref_data = ref_src->buffers[i_plane]; | 
 |     const int rec_stride = i_plane > 0 ? rec_dst->uv_stride : rec_dst->y_stride; | 
 |     const int ref_stride = i_plane > 0 ? ref_src->uv_stride : ref_src->y_stride; | 
 |     const int subsample_x = i_plane > 0 ? ref_src->subsampling_x : 0; | 
 |     const int subsample_y = i_plane > 0 ? ref_src->subsampling_y : 0; | 
 |     const uint64_t rec_offset = scaled_buffer_offset( | 
 |         x >> subsample_x, y >> subsample_y, rec_stride, NULL); | 
 |     const uint64_t ref_offset = scaled_buffer_offset( | 
 |         x >> subsample_x, y >> subsample_y, ref_stride, NULL); | 
 |     copy_tile(x_inside_boundary >> subsample_x, | 
 |               y_inside_boundary >> subsample_y, ref_data + ref_offset, | 
 |               ref_stride, rec_data + rec_offset, rec_stride); | 
 |   } | 
 |  | 
 |   if (cm->seq_params.order_hint_info.enable_ref_frame_mvs) { | 
 |     // copy mvs from cur frame to ref frame | 
 |     // It is ok to copy since all TMVP are collocated now | 
 |     bru_copy_sb_mvs(cm, -1, cm->bru.update_ref_idx, mi_row, mi_col, | 
 |                     x_inside_boundary >> MI_SIZE_LOG2, | 
 |                     y_inside_boundary >> MI_SIZE_LOG2); | 
 |   } | 
 | } | 
 |  | 
 | /* Set default inter mode for Support and Inactive SBs */ | 
 | void bru_set_default_inter_mb_mode_info(const AV1_COMMON *const cm, | 
 |                                         MACROBLOCKD *const xd, | 
 |                                         MB_MODE_INFO *const mbmi, | 
 |                                         BLOCK_SIZE bsize) { | 
 |   // think reuse init_mbmi() here | 
 |   mbmi->segment_id = 0; | 
 |   mbmi->skip_mode = 0; | 
 |   xd->tree_type = SHARED_PART; | 
 |   mbmi->skip_txfm[xd->tree_type == CHROMA_PART] = 1; | 
 |   mbmi->uv_mode = UV_DC_PRED; | 
 |   mbmi->palette_mode_info.palette_size[0] = 0; | 
 |   mbmi->palette_mode_info.palette_size[1] = 0; | 
 |   mbmi->fsc_mode[PLANE_TYPE_Y] = 0; | 
 |   mbmi->fsc_mode[PLANE_TYPE_UV] = 0; | 
 | #if CONFIG_NEW_CONTEXT_MODELING | 
 |   mbmi->use_intrabc[0] = 0; | 
 |   mbmi->use_intrabc[1] = 0; | 
 | #endif | 
 |   mbmi->bawp_flag[0] = 0; | 
 |   mbmi->bawp_flag[1] = 0; | 
 |   mbmi->cwp_idx = CWP_EQUAL; | 
 | #if CONFIG_IBC_SR_EXT | 
 |   mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0; | 
 | #endif  // CONFIG_IBC_SR_EXT | 
 | #if CONFIG_C076_INTER_MOD_CTX | 
 | #if CONFIG_REFINEMV | 
 |   mbmi->refinemv_flag = 0; | 
 | #endif  // CONFIG_REFINEMV | 
 | #endif  // CONFIG_C076_INTER_MOD_CTX | 
 | #if CONFIG_SEP_COMP_DRL | 
 |   mbmi->ref_mv_idx[0] = 0; | 
 |   mbmi->ref_mv_idx[1] = 0; | 
 | #else | 
 |   mbmi->ref_mv_idx = 0; | 
 | #endif | 
 |   mbmi->warp_ref_idx = 0; | 
 |   mbmi->max_num_warp_candidates = 0; | 
 |   mbmi->warpmv_with_mvd_flag = 0; | 
 |   mbmi->motion_mode = SIMPLE_TRANSLATION; | 
 |   mbmi->filter_intra_mode_info.use_filter_intra = 0; | 
 |   mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1); | 
 |   mbmi->comp_group_idx = 0; | 
 |   mbmi->interinter_comp.type = COMPOUND_AVERAGE; | 
 |   mbmi->mv[0].as_int = 0; | 
 |   mbmi->mv[1].as_int = 0; | 
 |   assert(cm->bru.update_ref_idx >= 0); | 
 | #if CONFIG_WARP_INTER_INTRA | 
 |   mbmi->warp_inter_intra = 0; | 
 | #endif | 
 |   // todo find del idx | 
 |   mbmi->ref_frame[0] = cm->bru.update_ref_idx; | 
 |   mbmi->ref_frame[1] = NONE_FRAME; | 
 |   mbmi->skip_mode = 0; | 
 |   mbmi->skip_txfm[xd->tree_type == CHROMA_PART] = 1; | 
 |   mbmi->mode = NEWMV; | 
 |   mbmi->region_type = MIXED_INTER_INTRA_REGION; | 
 |   mbmi->sb_type[0] = bsize; | 
 |   mbmi->sb_type[1] = bsize; | 
 |   mbmi->chroma_ref_info.bsize_base = bsize; | 
 |   mbmi->chroma_ref_info.bsize = bsize; | 
 |   xd->mi[0]->mi_col_start = xd->mi_col; | 
 |   xd->mi[0]->mi_row_start = xd->mi_row; | 
 |   xd->mi[0]->chroma_ref_info.mi_col_chroma_base = xd->mi_col; | 
 |   xd->mi[0]->chroma_ref_info.mi_row_chroma_base = xd->mi_row; | 
 |   xd->ccso_blk_y = 0; | 
 |   xd->ccso_blk_u = 0; | 
 |   xd->ccso_blk_v = 0; | 
 |   mbmi->ccso_blk_y = 0; | 
 |   mbmi->ccso_blk_u = 0; | 
 |   mbmi->ccso_blk_v = 0; | 
 |   mbmi->cdef_strength = -1; | 
 |   mbmi->local_rest_type = 0; | 
 |   mbmi->local_ccso_blk_flag = 0; | 
 |   set_default_max_mv_precision(mbmi, xd->sbi->sb_mv_precision); | 
 |   /// bru use only pixel precision | 
 |   set_mv_precision(mbmi, MV_PRECISION_ONE_PEL); | 
 |   // set_mv_precision(mbmi, mbmi->max_mv_precision); | 
 |   set_default_precision_set(cm, mbmi, cm->seq_params.sb_size); | 
 |   set_most_probable_mv_precision(cm, mbmi, cm->seq_params.sb_size); | 
 |   mbmi->interp_fltr = MULTITAP_SHARP; | 
 | #if !CONFIG_TX_PARTITION_CTX | 
 |   xd->above_txfm_context = | 
 |       cm->above_contexts.txfm[xd->tile.tile_row] + xd->mi_col; | 
 |   xd->left_txfm_context = | 
 |       xd->left_txfm_context_buffer + (xd->mi_row & MAX_MIB_MASK); | 
 | #endif | 
 |   if (is_bru_not_active_and_not_on_partial_border(cm, xd->mi_col, xd->mi_row, | 
 |                                                   bsize)) { | 
 |     mbmi->tx_size = TX_64X64; | 
 |   } else { | 
 |     mbmi->tx_size = tx_size_from_tx_mode(bsize, cm->features.tx_mode); | 
 |   } | 
 |   for (int plane = 0; plane < 1; plane++) { | 
 |     bru_update_txk_skip_array(cm, xd->mi_row, xd->mi_col, xd->tree_type, | 
 |                               &mbmi->chroma_ref_info, plane, MAX_MIB_SIZE, | 
 |                               MAX_MIB_SIZE); | 
 |   } | 
 | } | 
 |  | 
 | /* Core function of swap BRU reference frame and current frame for BRU optimized | 
 |  * decoder/encoder*/ | 
 | RefCntBuffer *bru_swap_common(AV1_COMMON *cm) { | 
 |   // should not use this function at all in none bru frames | 
 |   if (cm->bru.enabled) { | 
 |     assert(cm->bru.update_ref_idx >= 0); | 
 |     RefCntBuffer *ref_buf = get_ref_frame_buf(cm, cm->bru.update_ref_idx); | 
 |     assert(ref_buf != NULL); | 
 |     cm->bru.update_ref_fc = ref_buf->frame_context;  // pass all the values | 
 |     MV_REFERENCE_FRAME ref_frame; | 
 |     for (ref_frame = 0; ref_frame < INTER_REFS_PER_FRAME; ++ref_frame) { | 
 |       const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame); | 
 |       if (buf != NULL && ref_frame < cm->ref_frames_info.num_total_refs) { | 
 |         ref_buf->ref_order_hints[ref_frame] = buf->order_hint; | 
 |         ref_buf->ref_display_order_hint[ref_frame] = buf->display_order_hint; | 
 |       } else { | 
 |         ref_buf->ref_order_hints[ref_frame] = -1; | 
 |         ref_buf->ref_display_order_hint[ref_frame] = -1; | 
 |       } | 
 |     } | 
 | #if CONFIG_TEMP_LR | 
 |     RefCntBuffer *tmp_buf = cm->cur_frame; | 
 | #endif | 
 |     ref_buf->order_hint = cm->cur_frame->order_hint; | 
 |     ref_buf->display_order_hint = cm->cur_frame->display_order_hint; | 
 |     ref_buf->absolute_poc = cm->cur_frame->absolute_poc; | 
 |     ref_buf->pyramid_level = cm->cur_frame->pyramid_level; | 
 |     ref_buf->base_qindex = cm->cur_frame->base_qindex; | 
 |     ref_buf->num_ref_frames = cm->cur_frame->num_ref_frames; | 
 | #if CONFIG_OUTPUT_FRAME_BASED_ON_ORDER_HINT_ENHANCEMENT | 
 |     ref_buf->frame_output_done = 0; | 
 | #endif | 
 | #if CONFIG_TEMP_LR | 
 |     ref_buf->rst_info[0] = tmp_buf->rst_info[0]; | 
 |     ref_buf->rst_info[1] = tmp_buf->rst_info[1]; | 
 |     ref_buf->rst_info[2] = tmp_buf->rst_info[2]; | 
 |     av1_copy_rst_frame_filters(&ref_buf->rst_info[0], &tmp_buf->rst_info[0]); | 
 |     av1_copy_rst_frame_filters(&ref_buf->rst_info[1], &tmp_buf->rst_info[1]); | 
 |     av1_copy_rst_frame_filters(&ref_buf->rst_info[2], &tmp_buf->rst_info[2]); | 
 | #endif | 
 |     if (cm->bru.frame_inactive_flag) { | 
 |       ref_buf->ccso_info.ccso_frame_flag = 0; | 
 |     } else { | 
 |       ref_buf->ccso_info.ccso_frame_flag = tmp_buf->ccso_info.ccso_frame_flag; | 
 |     } | 
 |     for (int plane = 0; plane < CCSO_NUM_COMPONENTS; plane++) { | 
 |       if (cm->bru.frame_inactive_flag) { | 
 |         av1_copy_ccso_filters(&ref_buf->ccso_info, &cm->ccso_info, plane, 1, 0, | 
 |                               0); | 
 |         continue; | 
 |       } | 
 |       // copy from current to bru ref | 
 |       ref_buf->ccso_info.reuse_ccso[plane] = | 
 |           tmp_buf->ccso_info.reuse_ccso[plane]; | 
 |       ref_buf->ccso_info.sb_reuse_ccso[plane] = | 
 |           tmp_buf->ccso_info.sb_reuse_ccso[plane]; | 
 |       ref_buf->ccso_info.ccso_enable[plane] = | 
 |           tmp_buf->ccso_info.ccso_enable[plane]; | 
 |       ref_buf->ccso_info.ccso_ref_idx[plane] = | 
 |           tmp_buf->ccso_info.ccso_ref_idx[plane]; | 
 |       ref_buf->ccso_info.subsampling_x[plane] = | 
 |           plane > 0 ? cm->seq_params.subsampling_x : 0; | 
 |       ref_buf->ccso_info.subsampling_y[plane] = | 
 |           plane > 0 ? cm->seq_params.subsampling_y : 0; | 
 |       ref_buf->ccso_info.reuse_root_ref[plane] = | 
 |           tmp_buf->ccso_info.reuse_root_ref[plane]; | 
 | #if CONFIG_CCSO_FU_BUGFIX | 
 |       const int log2_filter_unit_size_y = | 
 |           plane == 0 ? CCSO_BLK_SIZE | 
 |                      : CCSO_BLK_SIZE - cm->seq_params.subsampling_y; | 
 |       const int log2_filter_unit_size_x = | 
 |           plane == 0 ? CCSO_BLK_SIZE | 
 |                      : CCSO_BLK_SIZE - cm->seq_params.subsampling_x; | 
 | #else | 
 |       const int log2_filter_unit_size_y = | 
 |           pli > 0 ? CCSO_BLK_SIZE | 
 |                   : CCSO_BLK_SIZE + cm->seq_params.subsampling_y; | 
 |       const int log2_filter_unit_size_x = | 
 |           pli > 0 ? CCSO_BLK_SIZE | 
 |                   : CCSO_BLK_SIZE + cm->seq_params.subsampling_x; | 
 | #endif  // CONFIG_CCSO_FU_BUGFIX | 
 |  | 
 |       const int ccso_nvfb = ((cm->mi_params.mi_rows >> | 
 |                               (plane ? cm->seq_params.subsampling_y : 0)) + | 
 |                              (1 << log2_filter_unit_size_y >> 2) - 1) / | 
 |                             (1 << log2_filter_unit_size_y >> 2); | 
 |       const int ccso_nhfb = ((cm->mi_params.mi_cols >> | 
 |                               (plane ? cm->seq_params.subsampling_x : 0)) + | 
 |                              (1 << log2_filter_unit_size_x >> 2) - 1) / | 
 |                             (1 << log2_filter_unit_size_x >> 2); | 
 |       const int sb_count = ccso_nvfb * ccso_nhfb; | 
 |       av1_copy_ccso_filters(&ref_buf->ccso_info, &tmp_buf->ccso_info, plane, 1, | 
 |                             1, sb_count); | 
 |     } | 
 |     // replace cur by bru_ref | 
 |     assign_frame_buffer_p(&cm->cur_frame, ref_buf); | 
 |     return ref_buf; | 
 |   } | 
 |   return NULL; | 
 | } |