summaryrefslogtreecommitdiff
path: root/vp9
diff options
context:
space:
mode:
authorDmitry Kovalev <dkovalev@google.com>2013-12-27 18:44:19 -0800
committerDmitry Kovalev <dkovalev@google.com>2014-01-03 15:21:55 -0800
commitba41e9d459c0f6384949a103eaaee7b631341def (patch)
treecd7f49a1c3e1c8f9bbd7a65f3a67906cc62e866e /vp9
parentefb150bb3092045b2f9011b4b7e35743689e5775 (diff)
downloadlibvpx-ba41e9d459c0f6384949a103eaaee7b631341def.tar
libvpx-ba41e9d459c0f6384949a103eaaee7b631341def.tar.gz
libvpx-ba41e9d459c0f6384949a103eaaee7b631341def.tar.bz2
libvpx-ba41e9d459c0f6384949a103eaaee7b631341def.zip
Adding RefBuffer struct.
Adding RefBuffer to simplify reference buffer management. The struct has a pointer to image data and scale factors relative to the current frame. Change-Id: If38eb1491ff687cc11428aee339f3e052e2c5d9e
Diffstat (limited to 'vp9')
-rw-r--r--vp9/common/vp9_alloccommon.c3
-rw-r--r--vp9/common/vp9_blockd.h12
-rw-r--r--vp9/common/vp9_onyxc_int.h11
-rw-r--r--vp9/common/vp9_reconinter.c17
-rw-r--r--vp9/common/vp9_reconinter.h6
-rw-r--r--vp9/decoder/vp9_decodeframe.c41
-rw-r--r--vp9/decoder/vp9_onyxd_if.c25
-rw-r--r--vp9/encoder/vp9_encodeframe.c3
-rw-r--r--vp9/encoder/vp9_onyx_if.c28
-rw-r--r--vp9/encoder/vp9_rdopt.c11
10 files changed, 75 insertions, 82 deletions
diff --git a/vp9/common/vp9_alloccommon.c b/vp9/common/vp9_alloccommon.c
index 6d485421a..ff20553d6 100644
--- a/vp9/common/vp9_alloccommon.c
+++ b/vp9/common/vp9_alloccommon.c
@@ -161,9 +161,6 @@ int vp9_alloc_frame_buffers(VP9_COMMON *cm, int width, int height) {
cm->new_fb_idx = cm->fb_count - 1;
cm->fb_idx_ref_cnt[cm->new_fb_idx] = 1;
- for (i = 0; i < REFS_PER_FRAME; i++)
- cm->active_ref_idx[i] = i;
-
for (i = 0; i < REF_FRAMES; i++) {
cm->ref_frame_map[i] = i;
cm->fb_idx_ref_cnt[i] = 1;
diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h
index 38acf1e6d..c6af7f6da 100644
--- a/vp9/common/vp9_blockd.h
+++ b/vp9/common/vp9_blockd.h
@@ -212,11 +212,17 @@ struct macroblockd_plane {
#define BLOCK_OFFSET(x, i) ((x) + (i) * 16)
+typedef struct RefBuffer {
+ // TODO(dkovalev): idx is not really required and should be removed, now it
+ // is used in vp9_onyxd_if.c
+ int idx;
+ YV12_BUFFER_CONFIG *buf;
+ struct scale_factors sf;
+} RefBuffer;
+
typedef struct macroblockd {
struct macroblockd_plane plane[MAX_MB_PLANE];
- const struct scale_factors *scale_factors[2];
-
MODE_INFO *last_mi;
int mode_info_stride;
@@ -235,7 +241,7 @@ typedef struct macroblockd {
int mb_to_bottom_edge;
/* pointers to reference frames */
- const YV12_BUFFER_CONFIG *ref_buf[2];
+ RefBuffer *block_refs[2];
/* pointer to current frame */
const YV12_BUFFER_CONFIG *cur_buf;
diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h
index ed4c044fe..b5ed959e1 100644
--- a/vp9/common/vp9_onyxc_int.h
+++ b/vp9/common/vp9_onyxc_int.h
@@ -121,8 +121,8 @@ typedef struct VP9Common {
// roll new_fb_idx into it.
// Each frame can reference REFS_PER_FRAME buffers
- int active_ref_idx[REFS_PER_FRAME];
- struct scale_factors active_ref_scale[REFS_PER_FRAME];
+ RefBuffer frame_refs[REFS_PER_FRAME];
+
int new_fb_idx;
YV12_BUFFER_CONFIG post_proc_buffer;
@@ -224,13 +224,6 @@ typedef struct VP9Common {
uint32_t fb_idx_ref_lru_count;
} VP9_COMMON;
-// ref == 0 => LAST_FRAME
-// ref == 1 => GOLDEN_FRAME
-// ref == 2 => ALTREF_FRAME
-static YV12_BUFFER_CONFIG *get_frame_ref_buffer(VP9_COMMON *cm, int ref) {
- return &cm->yv12_fb[cm->active_ref_idx[ref]];
-}
-
static YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) {
return &cm->yv12_fb[cm->new_fb_idx];
}
diff --git a/vp9/common/vp9_reconinter.c b/vp9/common/vp9_reconinter.c
index c84007e94..397f446f3 100644
--- a/vp9/common/vp9_reconinter.c
+++ b/vp9/common/vp9_reconinter.c
@@ -153,7 +153,7 @@ static void build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
int ref;
for (ref = 0; ref < 1 + is_compound; ++ref) {
- const struct scale_factors *const sf = xd->scale_factors[ref];
+ const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
struct buf_2d *const pre_buf = &pd->pre[ref];
struct buf_2d *const dst_buf = &pd->dst;
uint8_t *const dst = dst_buf->buf + dst_buf->stride * y + x;
@@ -256,7 +256,7 @@ static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
int ref;
for (ref = 0; ref < 1 + is_compound; ++ref) {
- const struct scale_factors *const sf = xd->scale_factors[ref];
+ const struct scale_factors *const sf = &xd->block_refs[ref]->sf;
struct buf_2d *const pre_buf = &pd->pre[ref];
struct buf_2d *const dst_buf = &pd->dst;
uint8_t *const dst = dst_buf->buf + dst_buf->stride * y + x;
@@ -283,7 +283,7 @@ static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block,
int xs, ys, x0, y0, x0_16, y0_16, x1, y1, frame_width,
frame_height, subpel_x, subpel_y;
uint8_t *ref_frame, *buf_ptr;
- const YV12_BUFFER_CONFIG *ref_buf = xd->ref_buf[ref];
+ const YV12_BUFFER_CONFIG *ref_buf = xd->block_refs[ref]->buf;
// Get reference frame pointer, width and height.
if (plane == 0) {
@@ -390,14 +390,3 @@ void vp9_dec_build_inter_predictors_sb(MACROBLOCKD *xd, int mi_row, int mi_col,
}
}
}
-
-// TODO(dkovalev: find better place for this function)
-void vp9_setup_scale_factors(VP9_COMMON *cm, int i) {
- const int ref = cm->active_ref_idx[i];
- struct scale_factors *const sf = &cm->active_ref_scale[i];
- YV12_BUFFER_CONFIG *const fb = &cm->yv12_fb[ref];
- vp9_setup_scale_factors_for_frame(sf,
- fb->y_crop_width, fb->y_crop_height,
- cm->width, cm->height);
-}
-
diff --git a/vp9/common/vp9_reconinter.h b/vp9/common/vp9_reconinter.h
index a4e968ce6..9f379399c 100644
--- a/vp9/common/vp9_reconinter.h
+++ b/vp9/common/vp9_reconinter.h
@@ -92,10 +92,8 @@ static void setup_pre_planes(MACROBLOCKD *xd, int i,
static void set_scale_factors(VP9_COMMON *cm, MACROBLOCKD *xd,
int ref0, int ref1) {
- xd->scale_factors[0] = &cm->active_ref_scale[ref0 >= 0 ? ref0 : 0];
- xd->scale_factors[1] = &cm->active_ref_scale[ref1 >= 0 ? ref1 : 0];
+ xd->block_refs[0] = &cm->frame_refs[ref0 >= 0 ? ref0 : 0];
+ xd->block_refs[1] = &cm->frame_refs[ref1 >= 0 ? ref1 : 0];
}
-void vp9_setup_scale_factors(VP9_COMMON *cm, int i);
-
#endif // VP9_COMMON_VP9_RECONINTER_H_
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c
index de6dbdcc0..59faccdf7 100644
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -378,18 +378,13 @@ static void set_offsets(VP9_COMMON *const cm, MACROBLOCKD *const xd,
static void set_ref(VP9_COMMON *const cm, MACROBLOCKD *const xd,
int idx, int mi_row, int mi_col) {
MB_MODE_INFO *const mbmi = &xd->mi_8x8[0]->mbmi;
- const int ref = mbmi->ref_frame[idx] - LAST_FRAME;
- const YV12_BUFFER_CONFIG *cfg = get_frame_ref_buffer(cm, ref);
- const struct scale_factors *sf = &cm->active_ref_scale[ref];
-
- xd->ref_buf[idx] = cfg;
- if (!vp9_is_valid_scale(sf))
+ RefBuffer *ref_buffer = &cm->frame_refs[mbmi->ref_frame[idx] - LAST_FRAME];
+ xd->block_refs[idx] = ref_buffer;
+ if (!vp9_is_valid_scale(&ref_buffer->sf))
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
"Invalid scale factors");
-
- xd->scale_factors[idx] = sf;
- setup_pre_planes(xd, idx, cfg, mi_row, mi_col, xd->scale_factors[idx]);
- xd->corrupted |= cfg->corrupted;
+ setup_pre_planes(xd, idx, ref_buffer->buf, mi_row, mi_col, &ref_buffer->sf);
+ xd->corrupted |= ref_buffer->buf->corrupted;
}
static void decode_modes_b(VP9_COMMON *const cm, MACROBLOCKD *const xd,
@@ -737,9 +732,9 @@ static void setup_frame_size_with_refs(VP9D_COMP *pbi,
int found = 0, i;
for (i = 0; i < REFS_PER_FRAME; ++i) {
if (vp9_rb_read_bit(rb)) {
- YV12_BUFFER_CONFIG *const cfg = get_frame_ref_buffer(cm, i);
- width = cfg->y_crop_width;
- height = cfg->y_crop_height;
+ YV12_BUFFER_CONFIG *const buf = cm->frame_refs[i].buf;
+ width = buf->y_crop_width;
+ height = buf->y_crop_height;
found = 1;
break;
}
@@ -1171,8 +1166,10 @@ static size_t read_uncompressed_header(VP9D_COMP *pbi,
pbi->refresh_frame_flags = (1 << REF_FRAMES) - 1;
- for (i = 0; i < REFS_PER_FRAME; ++i)
- cm->active_ref_idx[i] = cm->new_fb_idx;
+ for (i = 0; i < REFS_PER_FRAME; ++i) {
+ cm->frame_refs[i].idx = cm->new_fb_idx;
+ cm->frame_refs[i].buf = get_frame_new_buffer(cm);
+ }
setup_frame_size(pbi, rb);
} else {
@@ -1191,7 +1188,9 @@ static size_t read_uncompressed_header(VP9D_COMP *pbi,
for (i = 0; i < REFS_PER_FRAME; ++i) {
const int ref = vp9_rb_read_literal(rb, REF_FRAMES_LOG2);
- cm->active_ref_idx[i] = cm->ref_frame_map[ref];
+ const int idx = cm->ref_frame_map[ref];
+ cm->frame_refs[i].idx = idx;
+ cm->frame_refs[i].buf = &cm->yv12_fb[idx];
cm->ref_frame_sign_bias[LAST_FRAME + i] = vp9_rb_read_bit(rb);
}
@@ -1201,9 +1200,13 @@ static size_t read_uncompressed_header(VP9D_COMP *pbi,
cm->mcomp_filter_type = read_interp_filter_type(rb);
for (i = 0; i < REFS_PER_FRAME; ++i) {
- vp9_setup_scale_factors(cm, i);
- if (vp9_is_scaled(&cm->active_ref_scale[i]))
- vp9_extend_frame_borders(&cm->yv12_fb[cm->active_ref_idx[i]],
+ RefBuffer *const ref_buf = &cm->frame_refs[i];
+ vp9_setup_scale_factors_for_frame(&ref_buf->sf,
+ ref_buf->buf->y_crop_width,
+ ref_buf->buf->y_crop_height,
+ cm->width, cm->height);
+ if (vp9_is_scaled(&ref_buf->sf))
+ vp9_extend_frame_borders(ref_buf->buf,
cm->subsampling_x, cm->subsampling_y);
}
}
diff --git a/vp9/decoder/vp9_onyxd_if.c b/vp9/decoder/vp9_onyxd_if.c
index d585b9120..75d52c25a 100644
--- a/vp9/decoder/vp9_onyxd_if.c
+++ b/vp9/decoder/vp9_onyxd_if.c
@@ -219,7 +219,7 @@ vpx_codec_err_t vp9_set_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) {
VP9D_COMP *pbi = (VP9D_COMP *) ptr;
VP9_COMMON *cm = &pbi->common;
- int *ref_fb_ptr = NULL;
+ RefBuffer *ref_buf = NULL;
/* TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
* encoder is using the frame buffers for. This is just a stub to keep the
@@ -227,21 +227,23 @@ vpx_codec_err_t vp9_set_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag,
* later commit that adds VP9-specific controls for this functionality.
*/
if (ref_frame_flag == VP9_LAST_FLAG) {
- ref_fb_ptr = &pbi->common.active_ref_idx[0];
+ ref_buf = &cm->frame_refs[0];
} else if (ref_frame_flag == VP9_GOLD_FLAG) {
- ref_fb_ptr = &pbi->common.active_ref_idx[1];
+ ref_buf = &cm->frame_refs[1];
} else if (ref_frame_flag == VP9_ALT_FLAG) {
- ref_fb_ptr = &pbi->common.active_ref_idx[2];
+ ref_buf = &cm->frame_refs[2];
} else {
vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR,
"Invalid reference frame");
return pbi->common.error.error_code;
}
- if (!equal_dimensions(&cm->yv12_fb[*ref_fb_ptr], sd)) {
+ if (!equal_dimensions(ref_buf->buf, sd)) {
vpx_internal_error(&pbi->common.error, VPX_CODEC_ERROR,
"Incorrect buffer dimensions");
} else {
+ int *ref_fb_ptr = &ref_buf->idx;
+
// Find an empty frame buffer.
const int free_fb = get_free_fb(cm);
// Decrease fb_idx_ref_cnt since it will be increased again in
@@ -250,7 +252,8 @@ vpx_codec_err_t vp9_set_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag,
// Manage the reference counters and copy image.
ref_cnt_fb(cm->fb_idx_ref_cnt, ref_fb_ptr, free_fb);
- vp8_yv12_copy_frame(sd, &cm->yv12_fb[*ref_fb_ptr]);
+ ref_buf->buf = &cm->yv12_fb[*ref_fb_ptr];
+ vp8_yv12_copy_frame(sd, ref_buf->buf);
}
return pbi->common.error.error_code;
@@ -285,7 +288,7 @@ static void swap_frame_buffers(VP9D_COMP *pbi) {
// Invalidate these references until the next frame starts.
for (ref_index = 0; ref_index < 3; ref_index++)
- cm->active_ref_idx[ref_index] = INT_MAX;
+ cm->frame_refs[ref_index].idx = INT_MAX;
}
int vp9_receive_compressed_data(VP9D_PTR ptr,
@@ -317,8 +320,8 @@ int vp9_receive_compressed_data(VP9D_PTR ptr,
* at this point, but if it becomes so, [0] may not always be the correct
* thing to do here.
*/
- if (cm->active_ref_idx[0] != INT_MAX)
- get_frame_ref_buffer(cm, 0)->corrupted = 1;
+ if (cm->frame_refs[0].idx != INT_MAX)
+ cm->frame_refs[0].buf->corrupted = 1;
}
cm->new_fb_idx = get_free_fb(cm);
@@ -334,8 +337,8 @@ int vp9_receive_compressed_data(VP9D_PTR ptr,
* at this point, but if it becomes so, [0] may not always be the correct
* thing to do here.
*/
- if (cm->active_ref_idx[0] != INT_MAX)
- get_frame_ref_buffer(cm, 0)->corrupted = 1;
+ if (cm->frame_refs[0].idx != INT_MAX)
+ cm->frame_refs[0].buf->corrupted = 1;
if (cm->fb_idx_ref_cnt[cm->new_fb_idx] > 0)
cm->fb_idx_ref_cnt[cm->new_fb_idx]--;
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 800dc4995..c37a50e48 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -2588,9 +2588,8 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
for (ref = 0; ref < 1 + is_compound; ++ref) {
YV12_BUFFER_CONFIG *cfg = &cm->yv12_fb[cm->ref_frame_map[
get_ref_frame_idx(cpi, mbmi->ref_frame[ref])]];
- setup_pre_planes(xd, ref, cfg, mi_row, mi_col, xd->scale_factors[ref]);
+ setup_pre_planes(xd, ref, cfg, mi_row, mi_col, &xd->block_refs[ref]->sf);
}
-
vp9_build_inter_predictors_sb(xd, mi_row, mi_col, MAX(bsize, BLOCK_8X8));
}
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c
index 2e34b4a78..3758f1f59 100644
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -3317,6 +3317,7 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
VP9_COMMON *cm = &cpi->common;
struct vpx_usec_timer cmptimer;
YV12_BUFFER_CONFIG *force_src_buffer = NULL;
+ const int refs[] = { cpi->lst_fb_idx, cpi->gld_fb_idx, cpi->alt_fb_idx };
int i;
// FILE *fp_out = fopen("enc_frame_type.txt", "a");
@@ -3518,16 +3519,13 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
}
#endif
- /* Get the mapping of L/G/A to the reference buffer pool */
- cm->active_ref_idx[0] = cm->ref_frame_map[cpi->lst_fb_idx];
- cm->active_ref_idx[1] = cm->ref_frame_map[cpi->gld_fb_idx];
- cm->active_ref_idx[2] = cm->ref_frame_map[cpi->alt_fb_idx];
-
#if 0 // CONFIG_MULTIPLE_ARF
if (cpi->multi_arf_enabled) {
fprintf(fp_out, " idx(%d, %d, %d, %d) active(%d, %d, %d)",
cpi->lst_fb_idx, cpi->gld_fb_idx, cpi->alt_fb_idx, cm->new_fb_idx,
- cm->active_ref_idx[0], cm->active_ref_idx[1], cm->active_ref_idx[2]);
+ cm->ref_frame_map[cpi->lst_fb_idx],
+ cm->ref_frame_map[cpi->gld_fb_idx],
+ cm->ref_frame_map[cpi->alt_fb_idx]);
if (cpi->refresh_alt_ref_frame)
fprintf(fp_out, " type:ARF");
if (cpi->rc.is_src_frame_alt_ref)
@@ -3544,12 +3542,20 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
cm->subsampling_x, cm->subsampling_y,
VP9BORDERINPIXELS, NULL, NULL, NULL);
- // Calculate scaling factors for each of the 3 available references
+
for (i = 0; i < REFS_PER_FRAME; ++i) {
- vp9_setup_scale_factors(cm, i);
- if (vp9_is_scaled(&cm->active_ref_scale[i]))
- vp9_extend_frame_borders(&cm->yv12_fb[cm->active_ref_idx[i]],
- cm->subsampling_x, cm->subsampling_y);
+ const int idx = cm->ref_frame_map[refs[i]];
+ YV12_BUFFER_CONFIG *const buf = &cm->yv12_fb[idx];
+
+ RefBuffer *const ref_buf = &cm->frame_refs[i];
+ ref_buf->buf = buf;
+ ref_buf->idx = idx;
+ vp9_setup_scale_factors_for_frame(&ref_buf->sf,
+ buf->y_crop_width, buf->y_crop_height,
+ cm->width, cm->height);
+
+ if (vp9_is_scaled(&ref_buf->sf))
+ vp9_extend_frame_borders(buf, cm->subsampling_x, cm->subsampling_y);
}
vp9_setup_interp_filters(&cpi->mb.e_mbd, DEFAULT_INTERP_FILTER, cm);
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 22e480b11..561c0c312 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -1524,7 +1524,7 @@ static int64_t encode_inter_mb_segment(VP9_COMP *cpi,
vp9_build_inter_predictor(pre, pd->pre[ref].stride,
dst, pd->dst.stride,
&mi->bmi[i].as_mv[ref].as_mv,
- xd->scale_factors[ref],
+ &xd->block_refs[ref]->sf,
width, height, ref, &xd->subpix, MV_PRECISION_Q3,
mi_col * MI_SIZE + 4 * (i % 2),
mi_row * MI_SIZE + 4 * (i / 2));
@@ -2267,8 +2267,7 @@ static void setup_buffer_inter(VP9_COMP *cpi, MACROBLOCK *x,
YV12_BUFFER_CONFIG *yv12 = &cm->yv12_fb[cpi->common.ref_frame_map[idx]];
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mbmi = &xd->mi_8x8[0]->mbmi;
- const struct scale_factors *const sf =
- &cpi->common.active_ref_scale[frame_type - 1];
+ const struct scale_factors *const sf = &cm->frame_refs[frame_type - 1].sf;
// TODO(jkoleszar): Is the UV buffer ever used here? If so, need to make this
@@ -2539,7 +2538,7 @@ static void joint_motion_search(VP9_COMP *cpi, MACROBLOCK *x,
ref_yv12[!id].stride,
second_pred, pw,
&frame_mv[refs[!id]].as_mv,
- xd->scale_factors[!id],
+ &xd->block_refs[!id]->sf,
pw, ph, 0,
&xd->subpix, MV_PRECISION_Q3,
mi_col * MI_SIZE, mi_row * MI_SIZE);
@@ -3964,11 +3963,11 @@ int64_t vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x,
// TODO(jingning, jkoleszar): scaling reference frame not supported for
// sub8x8 blocks.
if (ref_frame > 0 &&
- vp9_is_scaled(&cpi->common.active_ref_scale[ref_frame - 1]))
+ vp9_is_scaled(&cpi->common.frame_refs[ref_frame - 1].sf))
continue;
if (second_ref_frame > 0 &&
- vp9_is_scaled(&cpi->common.active_ref_scale[second_ref_frame - 1]))
+ vp9_is_scaled(&cpi->common.frame_refs[second_ref_frame - 1].sf))
continue;
set_scale_factors(cm, xd, ref_frame - 1, second_ref_frame - 1);