Merge "Add get release decoder frame buffer functions."

This commit is contained in:
Frank Galligan 2014-02-11 08:19:37 -08:00 committed by Gerrit Code Review
commit d51ca0db00
14 changed files with 323 additions and 24 deletions

View File

@ -175,6 +175,7 @@ CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc
CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec
INSTALL-LIBS-yes += include/vpx/vpx_codec.h
INSTALL-LIBS-yes += include/vpx/vpx_frame_buffer.h
INSTALL-LIBS-yes += include/vpx/vpx_image.h
INSTALL-LIBS-yes += include/vpx/vpx_integer.h
INSTALL-LIBS-$(CONFIG_DECODERS) += include/vpx/vpx_decoder.h

View File

@ -33,9 +33,16 @@ void vp9_update_mode_info_border(VP9_COMMON *cm, MODE_INFO *mi) {
void vp9_free_frame_buffers(VP9_COMMON *cm) {
int i;
for (i = 0; i < FRAME_BUFFERS; i++)
for (i = 0; i < FRAME_BUFFERS; i++) {
vp9_free_frame_buffer(&cm->frame_bufs[i].buf);
if (cm->frame_bufs[i].ref_count > 0 &&
cm->frame_bufs[i].raw_frame_buffer.data != NULL) {
cm->release_fb_cb(cm->cb_priv, &cm->frame_bufs[i].raw_frame_buffer);
cm->frame_bufs[i].ref_count = 0;
}
}
vp9_free_frame_buffer(&cm->post_proc_buffer);
vpx_free(cm->mip);
@ -85,7 +92,7 @@ int vp9_resize_frame_buffers(VP9_COMMON *cm, int width, int height) {
int mi_size;
if (vp9_realloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y,
VP9_DEC_BORDER_IN_PIXELS) < 0)
VP9_DEC_BORDER_IN_PIXELS, NULL, NULL, NULL) < 0)
goto fail;
set_mb_mi(cm, aligned_width, aligned_height);
@ -199,6 +206,7 @@ void vp9_create_common(VP9_COMMON *cm) {
void vp9_remove_common(VP9_COMMON *cm) {
vp9_free_frame_buffers(cm);
vp9_free_internal_frame_buffers(&cm->int_frame_buffers);
}
void vp9_initialize_common() {

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <assert.h>
#include "vp9/common/vp9_frame_buffers.h"
#include "vpx_mem/vpx_mem.h"
int vp9_alloc_internal_frame_buffers(InternalFrameBufferList *list) {
assert(list != NULL);
vp9_free_internal_frame_buffers(list);
list->num_internal_frame_buffers =
VP9_MAXIMUM_REF_BUFFERS + VPX_MAXIMUM_WORK_BUFFERS;
list->int_fb = vpx_calloc(list->num_internal_frame_buffers,
sizeof(*list->int_fb));
return (list->int_fb == NULL);
}
void vp9_free_internal_frame_buffers(InternalFrameBufferList *list) {
int i;
assert(list != NULL);
for (i = 0; i < list->num_internal_frame_buffers; ++i) {
vpx_free(list->int_fb[i].data);
list->int_fb[i].data = NULL;
}
vpx_free(list->int_fb);
list->int_fb = NULL;
}
int vp9_get_frame_buffer(void *cb_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb) {
int i;
InternalFrameBufferList *const int_fb_list =
(InternalFrameBufferList *)cb_priv;
if (int_fb_list == NULL || fb == NULL)
return -1;
// Find a free frame buffer.
for (i = 0; i < int_fb_list->num_internal_frame_buffers; ++i) {
if (!int_fb_list->int_fb[i].in_use)
break;
}
if (i == int_fb_list->num_internal_frame_buffers)
return -1;
if (int_fb_list->int_fb[i].size < min_size) {
int_fb_list->int_fb[i].data =
(uint8_t *)vpx_realloc(int_fb_list->int_fb[i].data, min_size);
if (!int_fb_list->int_fb[i].data)
return -1;
int_fb_list->int_fb[i].size = min_size;
}
fb->data = int_fb_list->int_fb[i].data;
fb->size = int_fb_list->int_fb[i].size;
int_fb_list->int_fb[i].in_use = 1;
// Set the frame buffer's private data to point at the internal frame buffer.
fb->priv = &int_fb_list->int_fb[i];
return 0;
}
int vp9_release_frame_buffer(void *cb_priv, vpx_codec_frame_buffer_t *fb) {
InternalFrameBuffer *int_fb;
(void)cb_priv;
if (fb == NULL)
return -1;
int_fb = (InternalFrameBuffer *)fb->priv;
int_fb->in_use = 0;
return 0;
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VP9_COMMON_VP9_FRAME_BUFFERS_H_
#define VP9_COMMON_VP9_FRAME_BUFFERS_H_
#include "vpx/vpx_frame_buffer.h"
#include "vpx/vpx_integer.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct InternalFrameBuffer {
uint8_t *data;
size_t size;
int in_use;
} InternalFrameBuffer;
typedef struct InternalFrameBufferList {
int num_internal_frame_buffers;
InternalFrameBuffer *int_fb;
} InternalFrameBufferList;
// Initializes |list|. Returns 0 on success.
int vp9_alloc_internal_frame_buffers(InternalFrameBufferList *list);
// Free any data allocated to the frame buffers.
void vp9_free_internal_frame_buffers(InternalFrameBufferList *list);
// Callback used by libvpx to request an external frame buffer. |cb_priv|
// Callback private data, which points to an InternalFrameBufferList.
// |min_size| is the minimum size in bytes needed to decode the next frame.
// |fb| pointer to the frame buffer.
int vp9_get_frame_buffer(void *cb_priv, size_t min_size,
vpx_codec_frame_buffer_t *fb);
// Callback used by libvpx when there are no references to the frame buffer.
// |cb_priv| is not used. |fb| pointer to the frame buffer.
int vp9_release_frame_buffer(void *cb_priv, vpx_codec_frame_buffer_t *fb);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VP9_COMMON_VP9_FRAME_BUFFERS_H_

View File

@ -18,6 +18,7 @@
#include "vp9/common/vp9_entropymv.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_entropymode.h"
#include "vp9/common/vp9_frame_buffers.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_tile_common.h"
@ -94,6 +95,7 @@ typedef enum {
typedef struct {
int ref_count;
vpx_codec_frame_buffer_t raw_frame_buffer;
YV12_BUFFER_CONFIG buf;
} RefCntBuffer;
@ -223,6 +225,14 @@ typedef struct VP9Common {
int frame_parallel_decoding_mode;
int log2_tile_cols, log2_tile_rows;
// Private data associated with the frame buffer callbacks.
void *cb_priv;
vpx_get_frame_buffer_cb_fn_t get_fb_cb;
vpx_release_frame_buffer_cb_fn_t release_fb_cb;
// Handles memory for the codec.
InternalFrameBufferList int_frame_buffers;
} VP9_COMMON;
static INLINE YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) {

View File

@ -691,9 +691,14 @@ static void apply_frame_size(VP9D_COMP *pbi, int width, int height) {
vp9_update_frame_size(cm);
}
vp9_realloc_frame_buffer(get_frame_new_buffer(cm), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_DEC_BORDER_IN_PIXELS);
if (vp9_realloc_frame_buffer(
get_frame_new_buffer(cm), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y, VP9_DEC_BORDER_IN_PIXELS,
&cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer, cm->get_fb_cb,
cm->cb_priv)) {
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate frame buffer");
}
}
static void setup_frame_size(VP9D_COMP *pbi,
@ -1114,7 +1119,7 @@ static size_t read_uncompressed_header(VP9D_COMP *pbi,
cm->show_existing_frame = vp9_rb_read_bit(rb);
if (cm->show_existing_frame) {
// Show an existing frame directly.
int frame_to_show = cm->ref_frame_map[vp9_rb_read_literal(rb, 3)];
const int frame_to_show = cm->ref_frame_map[vp9_rb_read_literal(rb, 3)];
ref_cnt_fb(cm->frame_bufs, &cm->new_fb_idx, frame_to_show);
pbi->refresh_frame_flags = 0;
cm->lf.filter_level = 0;

View File

@ -290,9 +290,14 @@ static void swap_frame_buffers(VP9D_COMP *pbi) {
VP9_COMMON *const cm = &pbi->common;
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) {
if (mask & 1)
if (mask & 1) {
const int old_idx = cm->ref_frame_map[ref_index];
ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[ref_index],
cm->new_fb_idx);
if (old_idx >= 0 && cm->frame_bufs[old_idx].ref_count == 0)
cm->release_fb_cb(cm->cb_priv,
&cm->frame_bufs[old_idx].raw_frame_buffer);
}
++ref_index;
}

View File

@ -964,7 +964,7 @@ static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
cpi->oxcf.width, cpi->oxcf.height,
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,
"Failed to allocate altref buffer");
}
@ -1032,14 +1032,14 @@ static void update_frame_size(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
cm->width, cm->height,
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,
"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))
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate scaled source buffer");
@ -2674,7 +2674,7 @@ static void scale_references(VP9_COMP *cpi) {
vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS);
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf);
cpi->scaled_ref_idx[ref_frame - 1] = new_fb;
} else {
@ -3684,7 +3684,7 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
vp9_realloc_frame_buffer(get_frame_new_buffer(cm),
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
VP9_ENC_BORDER_IN_PIXELS);
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
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)];

View File

@ -23,6 +23,8 @@ VP9_COMMON_SRCS-yes += common/vp9_entropymode.c
VP9_COMMON_SRCS-yes += common/vp9_entropymv.c
VP9_COMMON_SRCS-yes += common/vp9_filter.c
VP9_COMMON_SRCS-yes += common/vp9_filter.h
VP9_COMMON_SRCS-yes += common/vp9_frame_buffers.c
VP9_COMMON_SRCS-yes += common/vp9_frame_buffers.h
VP9_COMMON_SRCS-yes += common/generic/vp9_systemdependent.c
VP9_COMMON_SRCS-yes += common/vp9_idct.c
VP9_COMMON_SRCS-yes += common/vp9_alloccommon.h

View File

@ -15,6 +15,7 @@
#include "vpx/vp8dx.h"
#include "vpx/internal/vpx_codec_internal.h"
#include "./vpx_version.h"
#include "vp9/common/vp9_frame_buffers.h"
#include "vp9/decoder/vp9_onyxd.h"
#include "vp9/decoder/vp9_onyxd_int.h"
#include "vp9/decoder/vp9_read_bit_buffer.h"
@ -293,10 +294,22 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
ctx->postproc_cfg.noise_level = 0;
}
if (!optr)
if (!optr) {
res = VPX_CODEC_ERROR;
else
} else {
VP9D_COMP *const pbi = (VP9D_COMP*)optr;
VP9_COMMON *const cm = &pbi->common;
cm->get_fb_cb = vp9_get_frame_buffer;
cm->release_fb_cb = vp9_release_frame_buffer;
if (vp9_alloc_internal_frame_buffers(&cm->int_frame_buffers))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to initialize internal frame buffers");
cm->cb_priv = &cm->int_frame_buffers;
ctx->pbi = optr;
}
}
ctx->decoder_init = 1;

View File

@ -26,6 +26,7 @@ API_DOC_SRCS-$(CONFIG_VP8_DECODER) += vp8dx.h
API_DOC_SRCS-yes += vpx_codec.h
API_DOC_SRCS-yes += vpx_decoder.h
API_DOC_SRCS-yes += vpx_encoder.h
API_DOC_SRCS-yes += vpx_frame_buffer.h
API_DOC_SRCS-yes += vpx_image.h
API_SRCS-yes += src/vpx_decoder.c
@ -37,5 +38,6 @@ API_SRCS-yes += src/vpx_codec.c
API_SRCS-yes += src/vpx_image.c
API_SRCS-yes += vpx_codec.h
API_SRCS-yes += vpx_codec.mk
API_SRCS-yes += vpx_frame_buffer.h
API_SRCS-yes += vpx_image.h
API_SRCS-$(BUILD_LIBVPX) += vpx_integer.h

74
vpx/vpx_frame_buffer.h Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2014 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VPX_VPX_FRAME_BUFFER_H_
#define VPX_VPX_FRAME_BUFFER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "./vpx_integer.h"
/*!\brief The maximum number of work buffers used by libvpx.
*/
#define VPX_MAXIMUM_WORK_BUFFERS 1
/*!\brief The maximum number of reference buffers that a VP9 encoder may use.
*/
#define VP9_MAXIMUM_REF_BUFFERS 8
/*!\brief External frame buffer
*
* This structure holds allocated frame buffers used by the decoder.
*/
typedef struct vpx_codec_frame_buffer {
uint8_t *data; /**< Pointer to the data buffer */
size_t size; /**< Size of data in bytes */
void *priv; /**< Frame's private data */
} vpx_codec_frame_buffer_t;
/*!\brief get frame buffer callback prototype
*
* This callback is invoked by the decoder to retrieve data for the frame
* buffer in order for the decode call to complete. The callback must
* allocate at least min_size in bytes and assign it to fb->data. Then the
* callback must set fb->size to the allocated size. The application does not
* need to align the allocated data. The callback is triggered when the
* decoder needs a frame buffer to decode a compressed image into. This
* function may be called more than once for every call to vpx_codec_decode.
* The application may set fb->priv to some data which will be passed
* back in the ximage and the release function call. On success the callback
* must return 0. Any failure the callback must return a value less than 0.
*
* \param[in] priv Callback's private data
* \param[in] new_size Size in bytes needed by the buffer
* \param[in,out] fb Pointer to vpx_codec_frame_buffer_t
*/
typedef int (*vpx_get_frame_buffer_cb_fn_t)(
void *priv, size_t min_size, vpx_codec_frame_buffer_t *fb);
/*!\brief release frame buffer callback prototype
*
* This callback is invoked by the decoder when the frame buffer is not
* referenced by any other buffers. On success the callback must return 0.
* Any failure the callback must return a value less than 0.
*
* \param[in] priv Callback's private data
* \param[in] fb Pointer to vpx_codec_frame_buffer_t
*/
typedef int (*vpx_release_frame_buffer_cb_fn_t)(
void *priv, vpx_codec_frame_buffer_t *fb);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // VPX_VPX_FRAME_BUFFER_H_

View File

@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <assert.h>
#include "./vpx_config.h"
#include "vpx_scale/yv12config.h"
#include "vpx_mem/vpx_mem.h"
@ -19,10 +21,17 @@
/****************************************************************************
*
****************************************************************************/
#define yv12_align_addr(addr, align) \
(void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align))
int
vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
if (ybf) {
vpx_free(ybf->buffer_alloc);
// If libvpx is using frame buffer callbacks then buffer_alloc_sz must
// not be set.
if (ybf->buffer_alloc_sz > 0) {
vpx_free(ybf->buffer_alloc);
}
/* buffer_alloc isn't accessed by most functions. Rather y_buffer,
u_buffer and v_buffer point to buffer_alloc and are used. Clear out
@ -108,7 +117,9 @@ int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
if (ybf) {
vpx_free(ybf->buffer_alloc);
if (ybf->buffer_alloc_sz > 0) {
vpx_free(ybf->buffer_alloc);
}
/* buffer_alloc isn't accessed by most functions. Rather y_buffer,
u_buffer and v_buffer point to buffer_alloc and are used. Clear out
@ -123,7 +134,10 @@ int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height,
int ss_x, int ss_y, int border) {
int ss_x, int ss_y, int border,
vpx_codec_frame_buffer_t *fb,
vpx_get_frame_buffer_cb_fn_t cb,
void *cb_priv) {
if (ybf) {
const int aligned_width = (width + 7) & ~7;
const int aligned_height = (height + 7) & ~7;
@ -148,7 +162,26 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
#else
const int frame_size = yplane_size + 2 * uvplane_size;
#endif
if (frame_size > ybf->buffer_alloc_sz) {
if (cb != NULL) {
const int align_addr_extra_size = 31;
const size_t external_frame_size = frame_size + align_addr_extra_size;
assert(fb != NULL);
// Allocation to hold larger frame, or first allocation.
if (cb(cb_priv, external_frame_size, fb) < 0)
return -1;
if (fb->data == NULL || fb->size < external_frame_size)
return -1;
// This memset is needed for fixing valgrind error from C loop filter
// due to access uninitialized memory in frame border. It could be
// removed if border is totally removed.
vpx_memset(fb->data, 0, fb->size);
ybf->buffer_alloc = yv12_align_addr(fb->data, 32);
} else if (frame_size > ybf->buffer_alloc_sz) {
// Allocation to hold larger frame, or first allocation.
if (ybf->buffer_alloc)
vpx_free(ybf->buffer_alloc);
@ -159,14 +192,11 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
ybf->buffer_alloc_sz = frame_size;
// This memset is needed for fixing valgrind error from C loop filter
// due to access uninitialized memory in frame boarder. It could be
// due to access uninitialized memory in frame border. It could be
// removed if border is totally removed.
vpx_memset(ybf->buffer_alloc, 0, ybf->buffer_alloc_sz);
}
if (ybf->buffer_alloc_sz < frame_size)
return -1;
/* Only support allocating buffers that have a border that's a multiple
* of 32. The border restriction is required to get 16-byte alignment of
* the start of the chroma rows without introducing an arbitrary gap
@ -214,7 +244,8 @@ int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int ss_x, int ss_y, int border) {
if (ybf) {
vp9_free_frame_buffer(ybf);
return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border);
return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border,
NULL, NULL, NULL);
}
return -2;
}

View File

@ -15,6 +15,7 @@
extern "C" {
#endif
#include "vpx/vpx_frame_buffer.h"
#include "vpx/vpx_integer.h"
#define VP8BORDERINPIXELS 32
@ -65,9 +66,19 @@ extern "C" {
int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, int ss_x, int ss_y,
int border);
// Updates the yv12 buffer config with the frame buffer. If cb is not
// NULL, then libvpx is using the frame buffer callbacks to handle memory.
// If cb is not NULL, libvpx will call cb with minimum size in bytes needed
// to decode the current frame. If cb is NULL, libvpx will allocate memory
// internally to decode the current frame. Returns 0 on success. Returns < 0
// on failure.
int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, int ss_x, int ss_y,
int border);
int border,
vpx_codec_frame_buffer_t *fb,
vpx_get_frame_buffer_cb_fn_t cb,
void *cb_priv);
int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf);
#ifdef __cplusplus