Commit e8e15279 authored by Frank Galligan's avatar Frank Galligan

Add get release decoder frame buffer functions.

This CL changes libvpx to call a function when a frame buffer
is needed for decode. Libvpx will call a release callback when
no other frames reference the frame buffer. This CL adds a
default implementation of the frame buffer callbacks. Currently
only VP9 is supported. A future CL will add support for
applications to supply their own frame buffer callbacks.

Change-Id: I1405a320118f1cdd95f80c670d52b085a62cb10d
parent 5f5c2627
...@@ -182,6 +182,7 @@ CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc ...@@ -182,6 +182,7 @@ CODEC_EXPORTS-$(CONFIG_ENCODERS) += vpx/exports_enc
CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec CODEC_EXPORTS-$(CONFIG_DECODERS) += vpx/exports_dec
INSTALL-LIBS-yes += include/vpx/vpx_codec.h 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_image.h
INSTALL-LIBS-yes += include/vpx/vpx_integer.h INSTALL-LIBS-yes += include/vpx/vpx_integer.h
INSTALL-LIBS-$(CONFIG_DECODERS) += include/vpx/vpx_decoder.h INSTALL-LIBS-$(CONFIG_DECODERS) += include/vpx/vpx_decoder.h
......
...@@ -33,9 +33,16 @@ void vp9_update_mode_info_border(VP9_COMMON *cm, MODE_INFO *mi) { ...@@ -33,9 +33,16 @@ void vp9_update_mode_info_border(VP9_COMMON *cm, MODE_INFO *mi) {
void vp9_free_frame_buffers(VP9_COMMON *cm) { void vp9_free_frame_buffers(VP9_COMMON *cm) {
int i; 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); 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); vp9_free_frame_buffer(&cm->post_proc_buffer);
vpx_free(cm->mip); vpx_free(cm->mip);
...@@ -85,7 +92,7 @@ int vp9_resize_frame_buffers(VP9_COMMON *cm, int width, int height) { ...@@ -85,7 +92,7 @@ int vp9_resize_frame_buffers(VP9_COMMON *cm, int width, int height) {
int mi_size; int mi_size;
if (vp9_realloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y, 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; goto fail;
set_mb_mi(cm, aligned_width, aligned_height); set_mb_mi(cm, aligned_width, aligned_height);
...@@ -199,6 +206,7 @@ void vp9_create_common(VP9_COMMON *cm) { ...@@ -199,6 +206,7 @@ void vp9_create_common(VP9_COMMON *cm) {
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_internal_frame_buffers(&cm->int_frame_buffers);
} }
void vp9_initialize_common() { void vp9_initialize_common() {
......
/*
* 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;
}
/*
* 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_
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "vp9/common/vp9_entropymv.h" #include "vp9/common/vp9_entropymv.h"
#include "vp9/common/vp9_entropy.h" #include "vp9/common/vp9_entropy.h"
#include "vp9/common/vp9_entropymode.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_quant_common.h"
#include "vp9/common/vp9_tile_common.h" #include "vp9/common/vp9_tile_common.h"
...@@ -94,6 +95,7 @@ typedef enum { ...@@ -94,6 +95,7 @@ typedef enum {
typedef struct { typedef struct {
int ref_count; int ref_count;
vpx_codec_frame_buffer_t raw_frame_buffer;
YV12_BUFFER_CONFIG buf; YV12_BUFFER_CONFIG buf;
} RefCntBuffer; } RefCntBuffer;
...@@ -223,6 +225,14 @@ typedef struct VP9Common { ...@@ -223,6 +225,14 @@ typedef struct VP9Common {
int frame_parallel_decoding_mode; int frame_parallel_decoding_mode;
int log2_tile_cols, log2_tile_rows; 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; } VP9_COMMON;
static YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) { static YV12_BUFFER_CONFIG *get_frame_new_buffer(VP9_COMMON *cm) {
......
...@@ -691,9 +691,14 @@ static void apply_frame_size(VP9D_COMP *pbi, int width, int height) { ...@@ -691,9 +691,14 @@ static void apply_frame_size(VP9D_COMP *pbi, int width, int height) {
vp9_update_frame_size(cm); vp9_update_frame_size(cm);
} }
vp9_realloc_frame_buffer(get_frame_new_buffer(cm), cm->width, cm->height, if (vp9_realloc_frame_buffer(
cm->subsampling_x, cm->subsampling_y, get_frame_new_buffer(cm), cm->width, cm->height,
VP9_DEC_BORDER_IN_PIXELS); 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, static void setup_frame_size(VP9D_COMP *pbi,
...@@ -1114,7 +1119,7 @@ static size_t read_uncompressed_header(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); cm->show_existing_frame = vp9_rb_read_bit(rb);
if (cm->show_existing_frame) { if (cm->show_existing_frame) {
// Show an existing frame directly. // 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); ref_cnt_fb(cm->frame_bufs, &cm->new_fb_idx, frame_to_show);
pbi->refresh_frame_flags = 0; pbi->refresh_frame_flags = 0;
cm->lf.filter_level = 0; cm->lf.filter_level = 0;
......
...@@ -290,9 +290,14 @@ static void swap_frame_buffers(VP9D_COMP *pbi) { ...@@ -290,9 +290,14 @@ static void swap_frame_buffers(VP9D_COMP *pbi) {
VP9_COMMON *const cm = &pbi->common; VP9_COMMON *const cm = &pbi->common;
for (mask = pbi->refresh_frame_flags; mask; mask >>= 1) { 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], ref_cnt_fb(cm->frame_bufs, &cm->ref_frame_map[ref_index],
cm->new_fb_idx); 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; ++ref_index;
} }
......
...@@ -963,7 +963,7 @@ static void alloc_raw_frame_buffers(VP9_COMP *cpi) { ...@@ -963,7 +963,7 @@ static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer, if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
cpi->oxcf.width, cpi->oxcf.height, cpi->oxcf.width, cpi->oxcf.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 altref buffer"); "Failed to allocate altref buffer");
} }
...@@ -1031,14 +1031,14 @@ static void update_frame_size(VP9_COMP *cpi) { ...@@ -1031,14 +1031,14 @@ static void update_frame_size(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->last_frame_uf, if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
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 reallocate last frame buffer"); "Failed to reallocate last frame buffer");
if (vp9_realloc_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 reallocate scaled source buffer"); "Failed to reallocate scaled source buffer");
...@@ -2551,7 +2551,7 @@ static void scale_references(VP9_COMP *cpi) { ...@@ -2551,7 +2551,7 @@ static void scale_references(VP9_COMP *cpi) {
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,
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);
scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf); scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf);
cpi->scaled_ref_idx[ref_frame - 1] = new_fb; cpi->scaled_ref_idx[ref_frame - 1] = new_fb;
} else { } else {
...@@ -3545,7 +3545,7 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags, ...@@ -3545,7 +3545,7 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags,
vp9_realloc_frame_buffer(get_frame_new_buffer(cm), vp9_realloc_frame_buffer(get_frame_new_buffer(cm),
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);
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)];
......
...@@ -23,6 +23,8 @@ VP9_COMMON_SRCS-yes += common/vp9_entropymode.c ...@@ -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_entropymv.c
VP9_COMMON_SRCS-yes += common/vp9_filter.c VP9_COMMON_SRCS-yes += common/vp9_filter.c
VP9_COMMON_SRCS-yes += common/vp9_filter.h 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/generic/vp9_systemdependent.c
VP9_COMMON_SRCS-yes += common/vp9_idct.c VP9_COMMON_SRCS-yes += common/vp9_idct.c
VP9_COMMON_SRCS-yes += common/vp9_alloccommon.h VP9_COMMON_SRCS-yes += common/vp9_alloccommon.h
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "vpx/vp8dx.h" #include "vpx/vp8dx.h"
#include "vpx/internal/vpx_codec_internal.h" #include "vpx/internal/vpx_codec_internal.h"
#include "./vpx_version.h" #include "./vpx_version.h"
#include "vp9/common/vp9_frame_buffers.h"
#include "vp9/decoder/vp9_onyxd.h" #include "vp9/decoder/vp9_onyxd.h"
#include "vp9/decoder/vp9_onyxd_int.h" #include "vp9/decoder/vp9_onyxd_int.h"
#include "vp9/decoder/vp9_read_bit_buffer.h" #include "vp9/decoder/vp9_read_bit_buffer.h"
...@@ -291,10 +292,22 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx, ...@@ -291,10 +292,22 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
ctx->postproc_cfg.noise_level = 0; ctx->postproc_cfg.noise_level = 0;
} }
if (!optr) if (!optr) {
res = VPX_CODEC_ERROR; 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->pbi = optr;
}
} }
ctx->decoder_init = 1; ctx->decoder_init = 1;
......
...@@ -26,6 +26,7 @@ API_DOC_SRCS-$(CONFIG_VP8_DECODER) += vp8dx.h ...@@ -26,6 +26,7 @@ API_DOC_SRCS-$(CONFIG_VP8_DECODER) += vp8dx.h
API_DOC_SRCS-yes += vpx_codec.h API_DOC_SRCS-yes += vpx_codec.h
API_DOC_SRCS-yes += vpx_decoder.h API_DOC_SRCS-yes += vpx_decoder.h
API_DOC_SRCS-yes += vpx_encoder.h API_DOC_SRCS-yes += vpx_encoder.h
API_DOC_SRCS-yes += vpx_frame_buffer.h
API_DOC_SRCS-yes += vpx_image.h API_DOC_SRCS-yes += vpx_image.h
API_SRCS-yes += src/vpx_decoder.c API_SRCS-yes += src/vpx_decoder.c
...@@ -37,5 +38,6 @@ API_SRCS-yes += src/vpx_codec.c ...@@ -37,5 +38,6 @@ API_SRCS-yes += src/vpx_codec.c
API_SRCS-yes += src/vpx_image.c API_SRCS-yes += src/vpx_image.c
API_SRCS-yes += vpx_codec.h API_SRCS-yes += vpx_codec.h
API_SRCS-yes += vpx_codec.mk API_SRCS-yes += vpx_codec.mk
API_SRCS-yes += vpx_frame_buffer.h
API_SRCS-yes += vpx_image.h API_SRCS-yes += vpx_image.h
API_SRCS-$(BUILD_LIBVPX) += vpx_integer.h API_SRCS-$(BUILD_LIBVPX) += vpx_integer.h
/*
* 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_
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <assert.h>
#include "./vpx_config.h" #include "./vpx_config.h"
#include "vpx_scale/yv12config.h" #include "vpx_scale/yv12config.h"
#include "vpx_mem/vpx_mem.h" #include "vpx_mem/vpx_mem.h"
...@@ -19,10 +21,17 @@ ...@@ -19,10 +21,17 @@
/**************************************************************************** /****************************************************************************
* *
****************************************************************************/ ****************************************************************************/
#define yv12_align_addr(addr, align) \
(void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align))
int int
vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) { vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
if (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, /* 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 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, ...@@ -108,7 +117,9 @@ int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) { int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
if (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, /* 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 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) { ...@@ -123,7 +134,10 @@ int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, 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) { if (ybf) {
const int aligned_width = (width + 7) & ~7; const int aligned_width = (width + 7) & ~7;
const int aligned_height = (height + 7) & ~7; const int aligned_height = (height + 7) & ~7;
...@@ -148,7 +162,26 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, ...@@ -148,7 +162,26 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
#else #else
const int frame_size = yplane_size + 2 * uvplane_size; const int frame_size = yplane_size + 2 * uvplane_size;
#endif #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. // Allocation to hold larger frame, or first allocation.
if (ybf->buffer_alloc) if (ybf->buffer_alloc)
vpx_free(ybf->buffer_alloc); vpx_free(ybf->buffer_alloc);
...@@ -159,14 +192,11 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, ...@@ -159,14 +192,11 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
ybf->buffer_alloc_sz = frame_size; ybf->buffer_alloc_sz = frame_size;
// This memset is needed for fixing valgrind error from C loop filter // 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. // removed if border is totally removed.
vpx_memset(ybf->buffer_alloc, 0, ybf->buffer_alloc_sz); 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 /* 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 * of 32. The border restriction is required to get 16-byte alignment of
* the start of the chroma rows without introducing an arbitrary gap * the start of the chroma rows without introducing an arbitrary gap
...@@ -214,7 +244,8 @@ int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, ...@@ -214,7 +244,8 @@ int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int ss_x, int ss_y, int border) { int ss_x, int ss_y, int border) {
if (ybf) { if (ybf) {
vp9_free_frame_buffer(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; return -2;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
extern "C" { extern "C" {
#endif #endif
#include "vpx/vpx_frame_buffer.h"
#include "vpx/vpx_integer.h" #include "vpx/vpx_integer.h"
#define VP8BORDERINPIXELS 32 #define VP8BORDERINPIXELS 32
...@@ -65,9 +66,19 @@ extern "C" { ...@@ -65,9 +66,19 @@ extern "C" {
int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, int ss_x, int ss_y, int width, int height, int ss_x, int ss_y,
int border); 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 vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, int ss_x, int ss_y, 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); int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf);
#ifdef __cplusplus #ifdef __cplusplus
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment