Allocate buffers based on correct chroma format

The encoder currently allocates frame buffers before
it establishes what the chroma sub-sampling factor is,
always allocating based on the 4:4:4 format.

This patch detects the chroma format as early as
possible allowing the encoder to allocate buffers of
the correct size.

Future patches will change the encoder to allocate
frame buffers on demand to further reduce the memory
profile of the encoder and rationalize the buffer
management in the encoder and decoder.

Change-Id: Ifd41dd96e67d0011719ba40fada0bae74f3a0d57
This commit is contained in:
Adrian Grange 2014-06-16 16:22:28 -07:00 committed by Gerrit Code Review
parent 97d0cb58f8
commit 8c1f071f1e
5 changed files with 91 additions and 75 deletions

View File

@ -109,7 +109,9 @@ void vp9_free_frame_buffers(VP9_COMMON *cm) {
} }
vp9_free_frame_buffer(&cm->post_proc_buffer); vp9_free_frame_buffer(&cm->post_proc_buffer);
}
void vp9_free_context_buffers(VP9_COMMON *cm) {
free_mi(cm); free_mi(cm);
vpx_free(cm->last_frame_seg_map); vpx_free(cm->last_frame_seg_map);
@ -165,37 +167,55 @@ int vp9_resize_frame_buffers(VP9_COMMON *cm, int width, int height) {
fail: fail:
vp9_free_frame_buffers(cm); vp9_free_frame_buffers(cm);
vp9_free_context_buffers(cm);
return 1; return 1;
} }
static void init_frame_bufs(VP9_COMMON *cm) {
int i;
cm->new_fb_idx = FRAME_BUFFERS - 1;
cm->frame_bufs[cm->new_fb_idx].ref_count = 1;
for (i = 0; i < REF_FRAMES; ++i) {
cm->ref_frame_map[i] = i;
cm->frame_bufs[i].ref_count = 1;
}
}
int vp9_alloc_frame_buffers(VP9_COMMON *cm, int width, int height) { int vp9_alloc_frame_buffers(VP9_COMMON *cm, int width, int height) {
const int aligned_width = ALIGN_POWER_OF_TWO(width, MI_SIZE_LOG2); int i;
const int aligned_height = ALIGN_POWER_OF_TWO(height, MI_SIZE_LOG2);
const int ss_x = cm->subsampling_x; const int ss_x = cm->subsampling_x;
const int ss_y = cm->subsampling_y; const int ss_y = cm->subsampling_y;
int i;
vp9_free_frame_buffers(cm); vp9_free_frame_buffers(cm);
for (i = 0; i < FRAME_BUFFERS; i++) { for (i = 0; i < FRAME_BUFFERS; ++i) {
cm->frame_bufs[i].ref_count = 0; cm->frame_bufs[i].ref_count = 0;
if (vp9_alloc_frame_buffer(&cm->frame_bufs[i].buf, width, height, if (vp9_alloc_frame_buffer(&cm->frame_bufs[i].buf, width, height,
ss_x, ss_y, VP9_ENC_BORDER_IN_PIXELS) < 0) ss_x, ss_y, VP9_ENC_BORDER_IN_PIXELS) < 0)
goto fail; goto fail;
} }
cm->new_fb_idx = FRAME_BUFFERS - 1; init_frame_bufs(cm);
cm->frame_bufs[cm->new_fb_idx].ref_count = 1;
for (i = 0; i < REF_FRAMES; i++) {
cm->ref_frame_map[i] = i;
cm->frame_bufs[i].ref_count = 1;
}
if (vp9_alloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y, if (vp9_alloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y,
VP9_ENC_BORDER_IN_PIXELS) < 0) VP9_ENC_BORDER_IN_PIXELS) < 0)
goto fail; goto fail;
return 0;
fail:
vp9_free_frame_buffers(cm);
return 1;
}
int vp9_alloc_context_buffers(VP9_COMMON *cm, int width, int height) {
const int aligned_width = ALIGN_POWER_OF_TWO(width, MI_SIZE_LOG2);
const int aligned_height = ALIGN_POWER_OF_TWO(height, MI_SIZE_LOG2);
vp9_free_context_buffers(cm);
set_mb_mi(cm, aligned_width, aligned_height); set_mb_mi(cm, aligned_width, aligned_height);
if (alloc_mi(cm, cm->mi_stride * (cm->mi_rows + MI_BLOCK_SIZE))) if (alloc_mi(cm, cm->mi_stride * (cm->mi_rows + MI_BLOCK_SIZE)))
@ -224,12 +244,13 @@ int vp9_alloc_frame_buffers(VP9_COMMON *cm, int width, int height) {
return 0; return 0;
fail: fail:
vp9_free_frame_buffers(cm); vp9_free_context_buffers(cm);
return 1; return 1;
} }
void vp9_remove_common(VP9_COMMON *cm) { void vp9_remove_common(VP9_COMMON *cm) {
vp9_free_frame_buffers(cm); vp9_free_frame_buffers(cm);
vp9_free_context_buffers(cm);
vp9_free_internal_frame_buffers(&cm->int_frame_buffers); vp9_free_internal_frame_buffers(&cm->int_frame_buffers);
} }

View File

@ -23,8 +23,12 @@ void vp9_remove_common(struct VP9Common *cm);
int vp9_resize_frame_buffers(struct VP9Common *cm, int width, int height); int vp9_resize_frame_buffers(struct VP9Common *cm, int width, int height);
int vp9_alloc_frame_buffers(struct VP9Common *cm, int width, int height); int vp9_alloc_frame_buffers(struct VP9Common *cm, int width, int height);
int vp9_alloc_state_buffers(struct VP9Common *cm, int width, int height);
int vp9_alloc_context_buffers(struct VP9Common *cm, int width, int height);
void vp9_free_frame_buffers(struct VP9Common *cm); void vp9_free_frame_buffers(struct VP9Common *cm);
void vp9_free_state_buffers(struct VP9Common *cm);
void vp9_free_context_buffers(struct VP9Common *cm);
void vp9_update_frame_size(struct VP9Common *cm); void vp9_update_frame_size(struct VP9Common *cm);

View File

@ -46,8 +46,8 @@ static INLINE int vp9_is_valid_scale(const struct scale_factors *sf) {
} }
static INLINE int vp9_is_scaled(const struct scale_factors *sf) { static INLINE int vp9_is_scaled(const struct scale_factors *sf) {
return sf->x_scale_fp != REF_NO_SCALE || return vp9_is_valid_scale(sf) &&
sf->y_scale_fp != REF_NO_SCALE; (sf->x_scale_fp != REF_NO_SCALE || sf->y_scale_fp != REF_NO_SCALE);
} }
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -178,6 +178,7 @@ static void dealloc_compressor_data(VP9_COMP *cpi) {
cpi->active_map = NULL; cpi->active_map = NULL;
vp9_free_frame_buffers(cm); vp9_free_frame_buffers(cm);
vp9_free_context_buffers(cm);
vp9_free_frame_buffer(&cpi->last_frame_uf); vp9_free_frame_buffer(&cpi->last_frame_uf);
vp9_free_frame_buffer(&cpi->scaled_source); vp9_free_frame_buffer(&cpi->scaled_source);
@ -415,39 +416,46 @@ static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
"Failed to allocate altref buffer"); "Failed to allocate altref buffer");
} }
void vp9_alloc_compressor_data(VP9_COMP *cpi) { static void alloc_ref_frame_buffers(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common; VP9_COMMON *const cm = &cpi->common;
if (vp9_alloc_frame_buffers(cm, cm->width, cm->height)) if (vp9_alloc_frame_buffers(cm, cm->width, cm->height))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate frame buffers"); "Failed to allocate frame buffers");
}
if (vp9_alloc_frame_buffer(&cpi->last_frame_uf, static void alloc_util_frame_buffers(VP9_COMP *cpi) {
cm->width, cm->height, VP9_COMMON *const cm = &cpi->common;
cm->subsampling_x, cm->subsampling_y, if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
VP9_ENC_BORDER_IN_PIXELS)) cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate last frame buffer"); "Failed to allocate last frame buffer");
if (vp9_alloc_frame_buffer(&cpi->scaled_source, if (vp9_realloc_frame_buffer(&cpi->scaled_source,
cm->width, cm->height, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y, cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS)) VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled source buffer"); "Failed to allocate scaled source buffer");
if (vp9_alloc_frame_buffer(&cpi->scaled_last_source, if (vp9_realloc_frame_buffer(&cpi->scaled_last_source,
cm->width, cm->height, cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y, cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS)) VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled last source buffer"); "Failed to allocate scaled last source buffer");
}
void vp9_alloc_compressor_data(VP9_COMP *cpi) {
VP9_COMMON *cm = &cpi->common;
vp9_alloc_context_buffers(cm, cm->width, cm->height);
vpx_free(cpi->tok); vpx_free(cpi->tok);
{ {
unsigned int tokens = get_token_alloc(cm->mb_rows, cm->mb_cols); unsigned int tokens = get_token_alloc(cm->mb_rows, cm->mb_cols);
CHECK_MEM_ERROR(cm, cpi->tok, vpx_calloc(tokens, sizeof(*cpi->tok))); CHECK_MEM_ERROR(cm, cpi->tok, vpx_calloc(tokens, sizeof(*cpi->tok)));
} }
@ -457,41 +465,7 @@ void vp9_alloc_compressor_data(VP9_COMP *cpi) {
static void update_frame_size(VP9_COMP *cpi) { static void update_frame_size(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common; VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &cpi->mb.e_mbd; MACROBLOCKD *const xd = &cpi->mb.e_mbd;
vp9_update_frame_size(cm); vp9_update_frame_size(cm);
// Update size of buffers local to this frame
if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate last frame buffer");
if (vp9_realloc_frame_buffer(&cpi->scaled_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate scaled source buffer");
if (vp9_realloc_frame_buffer(&cpi->scaled_last_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate scaled last source buffer");
{
int y_stride = cpi->scaled_source.y_stride;
if (cpi->sf.mv.search_method == NSTEP) {
vp9_init3smotion_compensation(&cpi->ss_cfg, y_stride);
} else if (cpi->sf.mv.search_method == DIAMOND) {
vp9_init_dsmotion_compensation(&cpi->ss_cfg, y_stride);
}
}
init_macroblockd(cm, xd); init_macroblockd(cm, xd);
} }
@ -529,8 +503,6 @@ static void init_config(struct VP9_COMP *cpi, VP9EncoderConfig *oxcf) {
cm->width = oxcf->width; cm->width = oxcf->width;
cm->height = oxcf->height; cm->height = oxcf->height;
cm->subsampling_x = 0;
cm->subsampling_y = 0;
vp9_alloc_compressor_data(cpi); vp9_alloc_compressor_data(cpi);
// Spatial scalability. // Spatial scalability.
@ -1612,8 +1584,7 @@ void vp9_scale_references(VP9_COMP *cpi) {
const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]; const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
const YV12_BUFFER_CONFIG *const ref = &cm->frame_bufs[idx].buf; const YV12_BUFFER_CONFIG *const ref = &cm->frame_bufs[idx].buf;
if (ref->y_crop_width != cm->width || if (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height) {
ref->y_crop_height != cm->height) {
const int new_fb = get_free_fb(cm); const int new_fb = get_free_fb(cm);
vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf, vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf,
cm->width, cm->height, cm->width, cm->height,
@ -2317,6 +2288,16 @@ static void Pass2Encode(VP9_COMP *cpi, size_t *size,
vp9_twopass_postencode_update(cpi); vp9_twopass_postencode_update(cpi);
} }
static void init_motion_estimation(VP9_COMP *cpi) {
int y_stride = cpi->scaled_source.y_stride;
if (cpi->sf.mv.search_method == NSTEP) {
vp9_init3smotion_compensation(&cpi->ss_cfg, y_stride);
} else if (cpi->sf.mv.search_method == DIAMOND) {
vp9_init_dsmotion_compensation(&cpi->ss_cfg, y_stride);
}
}
static void check_initial_width(VP9_COMP *cpi, int subsampling_x, static void check_initial_width(VP9_COMP *cpi, int subsampling_x,
int subsampling_y) { int subsampling_y) {
VP9_COMMON *const cm = &cpi->common; VP9_COMMON *const cm = &cpi->common;
@ -2324,7 +2305,13 @@ static void check_initial_width(VP9_COMP *cpi, int subsampling_x,
if (!cpi->initial_width) { if (!cpi->initial_width) {
cm->subsampling_x = subsampling_x; cm->subsampling_x = subsampling_x;
cm->subsampling_y = subsampling_y; cm->subsampling_y = subsampling_y;
alloc_raw_frame_buffers(cpi); alloc_raw_frame_buffers(cpi);
alloc_ref_frame_buffers(cpi);
alloc_util_frame_buffers(cpi);
init_motion_estimation(cpi);
cpi->initial_width = cm->width; cpi->initial_width = cm->width;
cpi->initial_height = cm->height; cpi->initial_height = cm->height;
} }
@ -2341,6 +2328,7 @@ int vp9_receive_raw_frame(VP9_COMP *cpi, unsigned int frame_flags,
const int subsampling_y = sd->uv_height < sd->y_height; const int subsampling_y = sd->uv_height < sd->y_height;
check_initial_width(cpi, subsampling_x, subsampling_y); check_initial_width(cpi, subsampling_x, subsampling_y);
vpx_usec_timer_start(&timer); vpx_usec_timer_start(&timer);
if (vp9_lookahead_push(cpi->lookahead, if (vp9_lookahead_push(cpi->lookahead,
sd, time_stamp, end_time, frame_flags)) sd, time_stamp, end_time, frame_flags))
@ -2545,11 +2533,11 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
cpi->un_scaled_source = cpi->Source = force_src_buffer ? force_src_buffer cpi->un_scaled_source = cpi->Source = force_src_buffer ? force_src_buffer
: &cpi->source->img; : &cpi->source->img;
if (cpi->last_source != NULL) { if (cpi->last_source != NULL) {
cpi->unscaled_last_source = &cpi->last_source->img; cpi->unscaled_last_source = &cpi->last_source->img;
} else { } else {
cpi->unscaled_last_source = NULL; cpi->unscaled_last_source = NULL;
} }
*time_stamp = cpi->source->ts_start; *time_stamp = cpi->source->ts_start;
*time_end = cpi->source->ts_end; *time_end = cpi->source->ts_end;
@ -2624,6 +2612,9 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
cm->subsampling_x, cm->subsampling_y, cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL); VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
alloc_util_frame_buffers(cpi);
init_motion_estimation(cpi);
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)]; const int idx = cm->ref_frame_map[get_ref_frame_idx(cpi, ref_frame)];
YV12_BUFFER_CONFIG *const buf = &cm->frame_bufs[idx].buf; YV12_BUFFER_CONFIG *const buf = &cm->frame_bufs[idx].buf;

View File

@ -497,6 +497,8 @@ void vp9_first_pass(VP9_COMP *cpi) {
&cpi->scaled_source); &cpi->scaled_source);
} }
vp9_setup_block_planes(&x->e_mbd, cm->subsampling_x, cm->subsampling_y);
vp9_setup_src_planes(x, cpi->Source, 0, 0); vp9_setup_src_planes(x, cpi->Source, 0, 0);
vp9_setup_pre_planes(xd, 0, first_ref_buf, 0, 0, NULL); vp9_setup_pre_planes(xd, 0, first_ref_buf, 0, 0, NULL);
vp9_setup_dst_planes(xd->plane, new_yv12, 0, 0); vp9_setup_dst_planes(xd->plane, new_yv12, 0, 0);
@ -504,8 +506,6 @@ void vp9_first_pass(VP9_COMP *cpi) {
xd->mi = cm->mi_grid_visible; xd->mi = cm->mi_grid_visible;
xd->mi[0] = cm->mi; xd->mi[0] = cm->mi;
vp9_setup_block_planes(&x->e_mbd, cm->subsampling_x, cm->subsampling_y);
vp9_frame_init_quantizer(cpi); vp9_frame_init_quantizer(cpi);
for (i = 0; i < MAX_MB_PLANE; ++i) { for (i = 0; i < MAX_MB_PLANE; ++i) {