From 7f6f4fe9c1b046bc5a3f9e41c261f47c6883a1dc Mon Sep 17 00:00:00 2001 From: Laurent Fasnacht Date: Mon, 5 May 2014 07:54:39 +0200 Subject: [PATCH] Reference count for picture --- src/encoder.c | 14 +++++++++----- src/picture.c | 27 +++++++++++++++++++-------- src/picture.h | 3 ++- src/threads.h | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 src/threads.h diff --git a/src/encoder.c b/src/encoder.c index 4f05dc93..d5dcebd3 100644 --- a/src/encoder.c +++ b/src/encoder.c @@ -442,7 +442,7 @@ static void encoder_clear_refs(encoder_state *encoder_state) { } while (encoder_state->ref->used_size) { - picture_list_rem(encoder_state->ref, encoder_state->ref->used_size - 1, 1); + picture_list_rem(encoder_state->ref, encoder_state->ref->used_size - 1); } encoder_state->poc = 0; @@ -1375,21 +1375,25 @@ static void encode_VUI(encoder_state * const encoder_state) void encoder_next_frame(encoder_state *encoder_state) { const encoder_control * const encoder = encoder_state->encoder_control; + picture *old_pic; // Remove the ref pic (if present) if (encoder_state->ref->used_size == (uint32_t)encoder->cfg->ref_frames) { - picture_list_rem(encoder_state->ref, encoder_state->ref->used_size-1, 1); + picture_list_rem(encoder_state->ref, encoder_state->ref->used_size-1); } // Add current picture as reference picture_list_add(encoder_state->ref, encoder_state->cur_pic); // Allocate new memory to current picture + old_pic = encoder_state->cur_pic; // TODO: reuse memory from old reference encoder_state->cur_pic = picture_alloc(encoder_state->cur_pic->width, encoder_state->cur_pic->height, encoder_state->cur_pic->width_in_lcu, encoder_state->cur_pic->height_in_lcu); // Copy pointer from the last cur_pic because we don't want to reallocate it - MOVE_POINTER(encoder_state->cur_pic->coeff_y,encoder_state->ref->pics[0]->coeff_y); - MOVE_POINTER(encoder_state->cur_pic->coeff_u,encoder_state->ref->pics[0]->coeff_u); - MOVE_POINTER(encoder_state->cur_pic->coeff_v,encoder_state->ref->pics[0]->coeff_v); + MOVE_POINTER(encoder_state->cur_pic->coeff_y,old_pic->coeff_y); + MOVE_POINTER(encoder_state->cur_pic->coeff_u,old_pic->coeff_u); + MOVE_POINTER(encoder_state->cur_pic->coeff_v,old_pic->coeff_v); + + picture_free(old_pic); encoder_state->frame++; encoder_state->poc++; diff --git a/src/picture.c b/src/picture.c index 83824788..64973c53 100644 --- a/src/picture.c +++ b/src/picture.c @@ -21,6 +21,7 @@ * \file */ +#include "threads.h" #include "picture.h" #include "strategyselector.h" @@ -192,6 +193,11 @@ int picture_list_destroy(picture_list *list) */ int picture_list_add(picture_list *list,picture* pic) { + if (ATOMIC_INC(&(pic->refcount)) == 1) { + fprintf(stderr, "Tried to add an unreferenced picture. This is a bug!\n"); + assert(0); //Stop for debugging + return 0; + } int i = 0; if (list->size == list->used_size) { if (!picture_list_resize(list, list->size*2)) return 0; @@ -212,7 +218,7 @@ int picture_list_add(picture_list *list,picture* pic) * \param picture_list list to use * \return 1 on success */ -int picture_list_rem(picture_list *list, unsigned n, int8_t destroy) +int picture_list_rem(picture_list * const list, const unsigned n) { // Must be within list boundaries if (n >= list->used_size) @@ -220,19 +226,21 @@ int picture_list_rem(picture_list *list, unsigned n, int8_t destroy) return 0; } - if (destroy) { - picture_free(list->pics[n]); - list->pics[n] = NULL; + if (!picture_free(list->pics[n])) { + fprintf(stderr, "Could not free picture!\n"); + assert(0); //Stop here + return 0; } - + // The last item is easy to remove if (n == list->used_size - 1) { list->pics[n] = NULL; list->used_size--; } else { + int i = n; // Shift all following pics one backward in the list - for (; n < list->used_size - 1; ++n) { - list->pics[n] = list->pics[n + 1]; + for (i = n; i < list->used_size - 1; ++i) { + list->pics[i] = list->pics[i + 1]; } list->pics[list->used_size - 1] = NULL; list->used_size--; @@ -262,6 +270,7 @@ picture *picture_alloc(const int32_t width, const int32_t height, pic->width_in_lcu = width_in_lcu; pic->height_in_lcu = height_in_lcu; pic->referenced = 0; + pic->refcount = 1; //We give a reference to caller // Allocate buffers pic->y_data = MALLOC(pixel, luma_size); pic->u_data = MALLOC(pixel, chroma_size); @@ -301,12 +310,14 @@ picture *picture_alloc(const int32_t width, const int32_t height, } /** - * \brief Free memory allocated to picture + * \brief Free memory allocated to picture (if we have no reference left) * \param pic picture pointer * \return 1 on success, 0 on failure */ int picture_free(picture * const pic) { + int32_t new_refcount = ATOMIC_DEC(&(pic->refcount)); + if (new_refcount > 0) return 1; free(pic->u_data); free(pic->v_data); free(pic->y_data); diff --git a/src/picture.h b/src/picture.h index de970bd5..b61d36f1 100644 --- a/src/picture.h +++ b/src/picture.h @@ -120,6 +120,7 @@ typedef struct picture_struct int32_t height_in_lcu; //!< \brief Picture width in number of LCU's. int32_t width_in_lcu; //!< \brief Picture height in number of LCU's. uint8_t referenced; //!< \brief Whether this picture is referenced. + int32_t refcount; //!< \brief Number of references in reflist to the picture cu_info* cu_array; //!< \brief Info for each CU at each depth. uint8_t type; uint8_t slicetype; @@ -224,7 +225,7 @@ picture_list * picture_list_init(int size); int picture_list_resize(picture_list *list, unsigned size); int picture_list_destroy(picture_list *list); int picture_list_add(picture_list *list, picture *pic); -int picture_list_rem(picture_list *list, unsigned n, int8_t destroy); +int picture_list_rem(picture_list *list, unsigned n); typedef unsigned (*cost_16bit_nxn_func)(pixel *block1, pixel *block2); diff --git a/src/threads.h b/src/threads.h new file mode 100644 index 00000000..42d9ac0e --- /dev/null +++ b/src/threads.h @@ -0,0 +1,37 @@ +#ifndef THREADS_H_ +#define THREADS_H_ +/***************************************************************************** + * This file is part of Kvazaar HEVC encoder. + * + * Copyright (C) 2013-2014 Tampere University of Technology and others (see + * COPYING file). + * + * Kvazaar is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * Kvazaar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kvazaar. If not, see . + ****************************************************************************/ + +#include + +#ifdef __GNUC__ + +#define ATOMIC_INC(ptr) __sync_add_and_fetch((volatile int32_t*)ptr, 1) +#define ATOMIC_DEC(ptr) __sync_add_and_fetch((volatile int32_t*)ptr, -1) + +#else //__GNUC__ + +//TODO: we assume !GCC => Windows... this may be bad +#define ATOMIC_INC(ptr) InterlockedIncrement((volatile LONG*)ptr) +#define ATOMIC_DEC(ptr) InterlockedDecrement((volatile LONG*)ptr) + +#endif //__GNUC__ + +#endif //THREADS_H_