Let subimages have multiple references.

Adds function image_copy_ref to image module for getting a new reference
to an image. It can be used instead of image_make_subimage when the
sizes of the original and the subimage are same.
This commit is contained in:
Arttu Ylä-Outinen 2015-06-17 11:06:09 +03:00
parent cec9b937dc
commit 50a5d5faa5
8 changed files with 100 additions and 72 deletions

View file

@ -105,9 +105,6 @@ static void encoder_state_config_tile_finalize(encoder_state_t * const state) {
yuv_t_free(state->tile->hor_buf_search); yuv_t_free(state->tile->hor_buf_search);
yuv_t_free(state->tile->ver_buf_search); yuv_t_free(state->tile->ver_buf_search);
if (state->tile->frame->source) image_free(state->tile->frame->source);
if (state->tile->frame->rec) image_free(state->tile->frame->rec);
videoframe_free(state->tile->frame); videoframe_free(state->tile->frame);
state->tile->frame = NULL; state->tile->frame = NULL;

View file

@ -879,6 +879,7 @@ int read_one_frame(FILE* file, const encoder_state_t * const state, image_t *img
int i; int i;
for (i = 0; i < state->encoder_control->cfg->gop_len; i++) { for (i = 0; i < state->encoder_control->cfg->gop_len; i++) {
gop_pictures[i].source = image_alloc(array_width, array_height); gop_pictures[i].source = image_alloc(array_width, array_height);
assert(gop_pictures[i].source);
} }
state->global->gop_offset = 0; state->global->gop_offset = 0;
gop_init = 1; gop_init = 1;
@ -980,7 +981,7 @@ void encoder_next_frame(encoder_state_t *state, image_t *img_in)
if (state->tile->frame->source) { if (state->tile->frame->source) {
image_free(state->tile->frame->source); image_free(state->tile->frame->source);
} }
state->tile->frame->source = image_make_subimage(img_in, 0, 0, state->tile->frame->width, state->tile->frame->height); state->tile->frame->source = image_copy_ref(img_in);
state->stats_done = 0; state->stats_done = 0;
@ -990,6 +991,7 @@ void encoder_next_frame(encoder_state_t *state, image_t *img_in)
state->global->poc = 0; state->global->poc = 0;
assert(!state->tile->frame->rec); assert(!state->tile->frame->rec);
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height); state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
assert(state->tile->frame->rec);
return; return;
} }
@ -1004,6 +1006,7 @@ void encoder_next_frame(encoder_state_t *state, image_t *img_in)
cu_array_free(state->tile->frame->cu_array); cu_array_free(state->tile->frame->cu_array);
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height); state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
assert(state->tile->frame->rec);
{ {
// Allocate height_in_scu x width_in_scu x sizeof(CU_info) // Allocate height_in_scu x width_in_scu x sizeof(CU_info)
unsigned height_in_scu = state->tile->frame->height_in_lcu << MAX_DEPTH; unsigned height_in_scu = state->tile->frame->height_in_lcu << MAX_DEPTH;
@ -1043,6 +1046,7 @@ void encoder_next_frame(encoder_state_t *state, image_t *img_in)
image_free(state->tile->frame->rec); image_free(state->tile->frame->rec);
state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height); state->tile->frame->rec = image_alloc(state->tile->frame->width, state->tile->frame->height);
assert(state->tile->frame->rec);
videoframe_set_poc(state->tile->frame, state->global->poc); videoframe_set_poc(state->tile->frame, state->global->poc);
} }

View file

@ -36,32 +36,34 @@
#include "sao.h" #include "sao.h"
/** /**
* \brief Allocate new image * \brief Allocate a new image.
* \return image pointer * \return image pointer or NULL on failure
*/ */
image_t *image_alloc(const int32_t width, const int32_t height) image_t *image_alloc(const int32_t width, const int32_t height)
{ {
image_t *im = MALLOC(image_t, 1);
unsigned int luma_size = width * height;
unsigned int chroma_size = luma_size / 4;
//Assert that we have a well defined image //Assert that we have a well defined image
assert((width % 2) == 0); assert((width % 2) == 0);
assert((height % 2) == 0); assert((height % 2) == 0);
image_t *im = MALLOC(image_t, 1);
if (!im) return NULL; if (!im) return NULL;
unsigned int luma_size = width * height;
unsigned int chroma_size = luma_size / 4;
//Allocate memory
im->fulldata = MALLOC(pixel_t, (luma_size + 2 * chroma_size));
if (!im->fulldata) {
free(im);
return NULL;
}
im->base_image = im;
im->refcount = 1; //We give a reference to caller
im->width = width; im->width = width;
im->height = height; im->height = height;
im->stride = width; im->stride = width;
im->base_image = im;
im->refcount = 1; //We give a reference to caller
//Allocate memory
im->fulldata = MALLOC(pixel_t, (luma_size + 2 * chroma_size));
im->y = im->data[COLOR_Y] = &im->fulldata[0]; im->y = im->data[COLOR_Y] = &im->fulldata[0];
im->u = im->data[COLOR_U] = &im->fulldata[luma_size]; im->u = im->data[COLOR_U] = &im->fulldata[luma_size];
im->v = im->data[COLOR_V] = &im->fulldata[luma_size + chroma_size]; im->v = im->data[COLOR_V] = &im->fulldata[luma_size + chroma_size];
@ -70,46 +72,59 @@ image_t *image_alloc(const int32_t width, const int32_t height)
} }
/** /**
* \brief Free memory allocated to picture (if we have no reference left) * \brief Free an image.
* \param pic picture pointer *
* \return 1 on success, 0 on failure * Decrement reference count of the image and deallocate associated memory
* if no references exist any more.
*
* \param im image to free
*/ */
int image_free(image_t * const im) void image_free(image_t * const im)
{ {
//Nothing to do if (im == NULL) return;
if (!im) return 1;
//Either we are the base image, or we should have no references int32_t new_refcount = ATOMIC_DEC(&(im->refcount));
assert(im->base_image == im || im->refcount == 0); if (new_refcount > 0) {
// There are still references so we don't free the data yet.
int32_t new_refcount = ATOMIC_DEC(&(im->base_image->refcount)); return;
//If we're freeing a subimage, then we must free the pointer
//Base image may be stored in image_list, and should not be freed
//FIXME I don't find this very clean...
if (new_refcount > 0 && im->base_image != im) free(im);
if (new_refcount > 0) return 1;
FREE_POINTER(im->base_image->fulldata);
//Just to make the program crash when using those values after the free
im->y = im->u = im->v = im->data[COLOR_Y] = im->data[COLOR_U] = im->data[COLOR_V] = NULL;
free(im);
return 1;
} }
if (im->base_image != im) {
// Free our reference to the base image.
image_free(im->base_image);
} else {
free(im->fulldata);
}
image_t *image_make_subimage(image_t * const orig_image, const unsigned int x_offset, const unsigned int y_offset, const unsigned int width, const unsigned int height) // Make sure freed data won't be used.
im->base_image = NULL;
im->fulldata = NULL;
im->y = im->u = im->v = NULL;
im->data[COLOR_Y] = im->data[COLOR_U] = im->data[COLOR_V] = NULL;
free(im);
}
/**
* \brief Get a new pointer to an image.
*
* Increment reference count and return the image.
*/
image_t *image_copy_ref(image_t *im)
{ {
image_t *im = MALLOC(image_t, 1); int32_t new_refcount = ATOMIC_INC(&(im->refcount));
if (!im) return NULL;
im->base_image = orig_image->base_image; // The caller should have had another reference.
ATOMIC_INC(&(im->base_image->refcount)); assert(new_refcount > 1);
assert(x_offset + width <= orig_image->width); return im;
assert(y_offset + height <= orig_image->height); }
image_t *image_make_subimage(image_t *const orig_image,
const unsigned x_offset,
const unsigned y_offset,
const unsigned width,
const unsigned height)
{
// Assert that we have a well defined image // Assert that we have a well defined image
assert((width % 2) == 0); assert((width % 2) == 0);
assert((height % 2) == 0); assert((height % 2) == 0);
@ -117,11 +132,17 @@ image_t *image_make_subimage(image_t * const orig_image, const unsigned int x_of
assert((x_offset % 2) == 0); assert((x_offset % 2) == 0);
assert((y_offset % 2) == 0); assert((y_offset % 2) == 0);
im->stride = orig_image->stride; assert(x_offset + width <= orig_image->width);
im->refcount = 0; //No references on subimages assert(y_offset + height <= orig_image->height);
image_t *im = MALLOC(image_t, 1);
if (!im) return NULL;
im->base_image = image_copy_ref(orig_image->base_image);
im->refcount = 1; // We give a reference to caller
im->width = width; im->width = width;
im->height = height; im->height = height;
im->stride = orig_image->stride;
im->y = im->data[COLOR_Y] = &orig_image->y[x_offset + y_offset * orig_image->stride]; im->y = im->data[COLOR_Y] = &orig_image->y[x_offset + y_offset * orig_image->stride];
im->u = im->data[COLOR_U] = &orig_image->u[x_offset/2 + y_offset/2 * orig_image->stride/2]; im->u = im->data[COLOR_U] = &orig_image->u[x_offset/2 + y_offset/2 * orig_image->stride/2];

View file

@ -43,8 +43,16 @@ typedef struct {
image_t *image_alloc(const int32_t width, const int32_t height); image_t *image_alloc(const int32_t width, const int32_t height);
int image_free(image_t * im);
image_t *image_make_subimage(image_t * const orig_image, const unsigned int x_offset, const unsigned int y_offset, const unsigned int width, const unsigned int height); void image_free(image_t *im);
image_t *image_copy_ref(image_t *im);
image_t *image_make_subimage(image_t *const orig_image,
const unsigned x_offset,
const unsigned y_offset,
const unsigned width,
const unsigned height);
yuv_t * yuv_t_alloc(int luma_size); yuv_t * yuv_t_alloc(int luma_size);
void yuv_t_free(yuv_t * yuv); void yuv_t_free(yuv_t * yuv);

View file

@ -150,11 +150,7 @@ int image_list_rem(image_list_t * const list, const unsigned n)
return 0; return 0;
} }
if (!image_free(list->images[n])) { image_free(list->images[n]);
fprintf(stderr, "Could not free image!\n");
assert(0); //Stop here
return 0;
}
if (!cu_array_free(list->cu_arrays[n])) { if (!cu_array_free(list->cu_arrays[n])) {
fprintf(stderr, "Could not free cu_array!\n"); fprintf(stderr, "Could not free cu_array!\n");

View file

@ -141,7 +141,7 @@ static int kvazaar_encode(kvz_encoder *enc, kvz_picture *img_in, kvz_picture **i
fflush(payload->file.output); fflush(payload->file.output);
} }
*img_out = image_make_subimage(state->tile->frame->rec, 0, 0, state->tile->frame->width, state->tile->frame->height); *img_out = image_copy_ref(state->tile->frame->rec);
enc->frames_done += 1; enc->frames_done += 1;
} }

View file

@ -66,7 +66,7 @@ typedef struct image_t {
int32_t stride; //!< \brief Luma pixel array width for the full picture (should be used as stride) int32_t stride; //!< \brief Luma pixel array width for the full picture (should be used as stride)
struct image_t * base_image; //!< \brief Pointer to the image to which the pixels belong struct image_t * base_image; //!< \brief Pointer to the image to which the pixels belong
int32_t refcount; //!< \brief Number of references in reflist to the picture int32_t refcount; //!< \brief Number of references to the picture
} image_t; } image_t;

View file

@ -71,8 +71,10 @@ videoframe_t *videoframe_alloc(const int32_t width, const int32_t height, const
*/ */
int videoframe_free(videoframe_t * const frame) int videoframe_free(videoframe_t * const frame)
{ {
//image_free(frame->source); image_free(frame->source);
//image_free(frame->rec); frame->source = NULL;
image_free(frame->rec);
frame->rec = NULL;
cu_array_free(frame->cu_array); cu_array_free(frame->cu_array);