Add VP9_GET_REFERENCE control

This is like VP8_COPY_REFERENCE, but returns a pointer to the reference
frame rather than a copy of it. This is useful when the application
doesn't know what the size of the reference is, as is the case when
scaling is in effect.

Change-Id: I63667109f65510364d0e397ebe56217140772085
This commit is contained in:
John Koleszar 2013-03-13 12:15:43 -07:00
parent bd9cd9a185
commit b3c350a1a9
10 changed files with 173 additions and 70 deletions

View File

@ -211,8 +211,10 @@ extern "C"
int vp9_update_reference(VP9_PTR comp, int ref_frame_flags);
int vp9_get_reference_enc(VP9_PTR comp, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
int vp9_copy_reference_enc(VP9_PTR comp, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
int vp9_get_reference_enc(VP9_PTR ptr, int index, YV12_BUFFER_CONFIG **fb);
int vp9_set_reference_enc(VP9_PTR comp, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);

View File

@ -46,14 +46,16 @@ extern "C" {
int64_t *time_stamp, int64_t *time_end_stamp,
vp9_ppflags_t *flags);
vpx_codec_err_t vp9_get_reference_dec(VP9D_PTR comp,
VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
vpx_codec_err_t vp9_copy_reference_dec(VP9D_PTR comp,
VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
vpx_codec_err_t vp9_set_reference_dec(VP9D_PTR comp,
VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd);
int vp9_get_reference_dec(VP9D_PTR ptr, int index, YV12_BUFFER_CONFIG **fb);
VP9D_PTR vp9_create_decompressor(VP9D_CONFIG *oxcf);
void vp9_remove_decompressor(VP9D_PTR comp);

View File

@ -164,8 +164,9 @@ void vp9_remove_decompressor(VP9D_PTR ptr) {
}
vpx_codec_err_t vp9_get_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) {
vpx_codec_err_t vp9_copy_reference_dec(VP9D_PTR ptr,
VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) {
VP9D_COMP *pbi = (VP9D_COMP *) ptr;
VP9_COMMON *cm = &pbi->common;
int ref_fb_idx;
@ -242,6 +243,17 @@ vpx_codec_err_t vp9_set_reference_dec(VP9D_PTR ptr, VP9_REFFRAME ref_frame_flag,
}
int vp9_get_reference_dec(VP9D_PTR ptr, int index, YV12_BUFFER_CONFIG **fb) {
VP9D_COMP *pbi = (VP9D_COMP *) ptr;
VP9_COMMON *cm = &pbi->common;
if (index < 0 || index >= NUM_REF_FRAMES)
return -1;
*fb = &cm->yv12_fb[cm->ref_frame_map[index]];
return 0;
}
/* If any buffer updating is signalled it should be done here. */
static void swap_frame_buffers(VP9D_COMP *pbi) {
int ref_index = 0, mask;

View File

@ -2103,8 +2103,8 @@ int vp9_update_reference(VP9_PTR ptr, int ref_frame_flags) {
return 0;
}
int vp9_get_reference_enc(VP9_PTR ptr, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) {
int vp9_copy_reference_enc(VP9_PTR ptr, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) {
VP9_COMP *cpi = (VP9_COMP *)(ptr);
VP9_COMMON *cm = &cpi->common;
int ref_fb_idx;
@ -2123,6 +2123,17 @@ int vp9_get_reference_enc(VP9_PTR ptr, VP9_REFFRAME ref_frame_flag,
return 0;
}
int vp9_get_reference_enc(VP9_PTR ptr, int index, YV12_BUFFER_CONFIG **fb) {
VP9_COMP *cpi = (VP9_COMP *)(ptr);
VP9_COMMON *cm = &cpi->common;
if (index < 0 || index >= NUM_REF_FRAMES)
return -1;
*fb = &cm->yv12_fb[cm->ref_frame_map[index]];
return 0;
}
int vp9_set_reference_enc(VP9_PTR ptr, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) {
VP9_COMP *cpi = (VP9_COMP *)(ptr);

View File

@ -9,6 +9,7 @@
##
VP9_COMMON_SRCS-yes += vp9_common.mk
VP9_COMMON_SRCS-yes += vp9_iface_common.h
VP9_COMMON_SRCS-yes += common/vp9_pragmas.h
VP9_COMMON_SRCS-yes += common/vp9_ppflags.h
VP9_COMMON_SRCS-yes += common/vp9_onyx.h

View File

@ -16,6 +16,7 @@
#include "vpx/vp8cx.h"
#include "vp9/encoder/vp9_firstpass.h"
#include "vp9/common/vp9_onyx.h"
#include "vp9/vp9_iface_common.h"
#include <stdlib.h>
#include <string.h>
@ -867,9 +868,9 @@ static vpx_codec_err_t vp8e_set_reference(vpx_codec_alg_priv_t *ctx,
}
static vpx_codec_err_t vp8e_get_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
static vpx_codec_err_t vp8e_copy_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
@ -878,12 +879,28 @@ static vpx_codec_err_t vp8e_get_reference(vpx_codec_alg_priv_t *ctx,
YV12_BUFFER_CONFIG sd;
image2yuvconfig(&frame->img, &sd);
vp9_get_reference_enc(ctx->cpi, frame->frame_type, &sd);
vp9_copy_reference_enc(ctx->cpi, frame->frame_type, &sd);
return VPX_CODEC_OK;
} else
return VPX_CODEC_INVALID_PARAM;
}
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);
if (data) {
YV12_BUFFER_CONFIG* fb;
vp9_get_reference_enc(ctx->cpi, data->idx, &fb);
yuvconfig2image(&data->img, fb, NULL);
return VPX_CODEC_OK;
} else {
return VPX_CODEC_INVALID_PARAM;
}
}
static vpx_codec_err_t vp8e_set_previewpp(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
@ -1038,7 +1055,7 @@ static vpx_codec_err_t vp8e_set_scalemode(vpx_codec_alg_priv_t *ctx,
static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] = {
{VP8_SET_REFERENCE, vp8e_set_reference},
{VP8_COPY_REFERENCE, vp8e_get_reference},
{VP8_COPY_REFERENCE, vp8e_copy_reference},
{VP8_SET_POSTPROC, vp8e_set_previewpp},
{VP8E_UPD_ENTROPY, vp8e_update_entropy},
{VP8E_UPD_REFERENCE, vp8e_update_reference},
@ -1062,6 +1079,7 @@ static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] = {
{VP8E_SET_CQ_LEVEL, set_param},
{VP8E_SET_MAX_INTRA_BITRATE_PCT, set_param},
{VP9E_SET_LOSSLESS, set_param},
{VP9_GET_REFERENCE, get_reference},
{ -1, NULL},
};

View File

@ -17,6 +17,7 @@
#include "vpx_version.h"
#include "decoder/vp9_onyxd.h"
#include "decoder/vp9_onyxd_int.h"
#include "vp9/vp9_iface_common.h"
#define VP8_CAP_POSTPROC (CONFIG_POSTPROC ? VPX_CODEC_CAP_POSTPROC : 0)
typedef vpx_codec_stream_info_t vp8_stream_info_t;
@ -273,36 +274,6 @@ update_error_state(vpx_codec_alg_priv_t *ctx,
return res;
}
static void yuvconfig2image(vpx_image_t *img,
const YV12_BUFFER_CONFIG *yv12,
void *user_priv) {
/** vpx_img_wrap() doesn't allow specifying independent strides for
* the Y, U, and V planes, nor other alignment adjustments that
* might be representable by a YV12_BUFFER_CONFIG, so we just
* initialize all the fields.*/
img->fmt = yv12->clrtype == REG_YUV ?
VPX_IMG_FMT_I420 : VPX_IMG_FMT_VPXI420;
img->w = yv12->y_stride;
img->h = (yv12->y_height + 2 * VP9BORDERINPIXELS + 15) & ~15;
img->d_w = yv12->y_width;
img->d_h = yv12->y_height;
img->x_chroma_shift = 1;
img->y_chroma_shift = 1;
img->planes[VPX_PLANE_Y] = yv12->y_buffer;
img->planes[VPX_PLANE_U] = yv12->u_buffer;
img->planes[VPX_PLANE_V] = yv12->v_buffer;
img->planes[VPX_PLANE_ALPHA] = NULL;
img->stride[VPX_PLANE_Y] = yv12->y_stride;
img->stride[VPX_PLANE_U] = yv12->uv_stride;
img->stride[VPX_PLANE_V] = yv12->uv_stride;
img->stride[VPX_PLANE_ALPHA] = yv12->y_stride;
img->bps = 12;
img->user_priv = user_priv;
img->img_data = yv12->buffer_alloc;
img->img_data_owner = 0;
img->self_allocd = 0;
}
static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx,
const uint8_t **data,
unsigned int data_sz,
@ -648,9 +619,9 @@ static vpx_codec_err_t vp9_set_reference(vpx_codec_alg_priv_t *ctx,
}
static vpx_codec_err_t vp9_get_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
static vpx_codec_err_t vp9_copy_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
@ -660,13 +631,29 @@ static vpx_codec_err_t vp9_get_reference(vpx_codec_alg_priv_t *ctx,
image2yuvconfig(&frame->img, &sd);
return vp9_get_reference_dec(ctx->pbi,
(VP9_REFFRAME)frame->frame_type, &sd);
return vp9_copy_reference_dec(ctx->pbi,
(VP9_REFFRAME)frame->frame_type, &sd);
} else
return VPX_CODEC_INVALID_PARAM;
}
static vpx_codec_err_t get_reference(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
vp9_ref_frame_t *data = va_arg(args, vp9_ref_frame_t *);
if (data) {
YV12_BUFFER_CONFIG* fb;
vp9_get_reference_dec(ctx->pbi, data->idx, &fb);
yuvconfig2image(&data->img, fb, NULL);
return VPX_CODEC_OK;
} else {
return VPX_CODEC_INVALID_PARAM;
}
}
static vpx_codec_err_t vp8_set_postproc(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
@ -739,7 +726,7 @@ static vpx_codec_err_t vp8_get_frame_corrupted(vpx_codec_alg_priv_t *ctx,
static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
{VP8_SET_REFERENCE, vp9_set_reference},
{VP8_COPY_REFERENCE, vp9_get_reference},
{VP8_COPY_REFERENCE, vp9_copy_reference},
{VP8_SET_POSTPROC, vp8_set_postproc},
{VP8_SET_DBG_COLOR_REF_FRAME, vp8_set_dbg_options},
{VP8_SET_DBG_COLOR_MB_MODES, vp8_set_dbg_options},
@ -747,6 +734,7 @@ static vpx_codec_ctrl_fn_map_t ctf_maps[] = {
{VP8_SET_DBG_DISPLAY_MV, vp8_set_dbg_options},
{VP8D_GET_LAST_REF_UPDATES, vp8_get_last_ref_updates},
{VP8D_GET_FRAME_CORRUPTED, vp8_get_frame_corrupted},
{VP9_GET_REFERENCE, get_reference},
{ -1, NULL},
};

43
vp9/vp9_iface_common.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2013 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_VP9_IFACE_COMMON_H_
#define VP9_VP9_IFACE_COMMON_H_
static void yuvconfig2image(vpx_image_t *img,
const YV12_BUFFER_CONFIG *yv12,
void *user_priv) {
/** vpx_img_wrap() doesn't allow specifying independent strides for
* the Y, U, and V planes, nor other alignment adjustments that
* might be representable by a YV12_BUFFER_CONFIG, so we just
* initialize all the fields.*/
img->fmt = yv12->clrtype == REG_YUV ?
VPX_IMG_FMT_I420 : VPX_IMG_FMT_VPXI420;
img->w = yv12->y_stride;
img->h = (yv12->y_height + 2 * VP9BORDERINPIXELS + 15) & ~15;
img->d_w = yv12->y_width;
img->d_h = yv12->y_height;
img->x_chroma_shift = 1;
img->y_chroma_shift = 1;
img->planes[VPX_PLANE_Y] = yv12->y_buffer;
img->planes[VPX_PLANE_U] = yv12->u_buffer;
img->planes[VPX_PLANE_V] = yv12->v_buffer;
img->planes[VPX_PLANE_ALPHA] = NULL;
img->stride[VPX_PLANE_Y] = yv12->y_stride;
img->stride[VPX_PLANE_U] = yv12->uv_stride;
img->stride[VPX_PLANE_V] = yv12->uv_stride;
img->stride[VPX_PLANE_ALPHA] = yv12->y_stride;
img->bps = 12;
img->user_priv = user_priv;
img->img_data = yv12->buffer_alloc;
img->img_data_owner = 0;
img->self_allocd = 0;
}
#endif

View File

@ -44,6 +44,12 @@ enum vp8_com_control_id {
VP8_SET_DBG_COLOR_MB_MODES = 5, /**< set which macro block modes to color */
VP8_SET_DBG_COLOR_B_MODES = 6, /**< set which blocks modes to color */
VP8_SET_DBG_DISPLAY_MV = 7, /**< set which motion vector modes to draw */
/* TODO(jkoleszar): The encoder incorrectly reuses some of these values (5+)
* for its control ids. These should be migrated to something like the
* VP8_DECODER_CTRL_ID_START range next time we're ready to break the ABI.
*/
VP9_GET_REFERENCE = 128, /**< get a pointer to a reference frame */
VP8_COMMON_CTRL_ID_MAX,
VP8_DECODER_CTRL_ID_START = 256
};
@ -97,6 +103,10 @@ typedef struct vpx_ref_frame {
vpx_image_t img; /**< reference frame data in image format */
} vpx_ref_frame_t;
typedef struct vp9_ref_frame {
int idx; /**< frame index to get (input) */
vpx_image_t img; /**< img structure to populate (output) */
} vp9_ref_frame_t;
/*!\brief vp8 decoder control function parameter type
*
@ -110,6 +120,7 @@ VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_REF_FRAME, int)
VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_MB_MODES, int)
VPX_CTRL_USE_TYPE(VP8_SET_DBG_COLOR_B_MODES, int)
VPX_CTRL_USE_TYPE(VP8_SET_DBG_DISPLAY_MV, int)
VPX_CTRL_USE_TYPE(VP9_GET_REFERENCE, vp9_ref_frame_t *)
/*! @} - end defgroup vp8 */

View File

@ -1645,8 +1645,6 @@ struct stream_state {
stats_io_t stats;
struct vpx_image *img;
vpx_codec_ctx_t decoder;
vpx_ref_frame_t ref_enc;
vpx_ref_frame_t ref_dec;
int mismatch_seen;
};
@ -2235,16 +2233,7 @@ static void initialize_encoder(struct stream_state *stream,
#if CONFIG_DECODERS
if (global->test_decode != TEST_DECODE_OFF) {
int width, height;
vpx_codec_dec_init(&stream->decoder, global->codec->dx_iface(), NULL, 0);
width = (stream->config.cfg.g_w + 15) & ~15;
height = (stream->config.cfg.g_h + 15) & ~15;
vpx_img_alloc(&stream->ref_enc.img, VPX_IMG_FMT_I420, width, height, 1);
vpx_img_alloc(&stream->ref_dec.img, VPX_IMG_FMT_I420, width, height, 1);
stream->ref_enc.frame_type = VP8_LAST_FRAME;
stream->ref_dec.frame_type = VP8_LAST_FRAME;
}
#endif
}
@ -2429,19 +2418,44 @@ static float usec_to_fps(uint64_t usec, unsigned int frames) {
static void test_decode(struct stream_state *stream,
enum TestDecodeFatality fatal) {
enum TestDecodeFatality fatal,
const struct codec_item *codec) {
vpx_image_t enc_img, dec_img;
if (stream->mismatch_seen)
return;
vpx_codec_control(&stream->encoder, VP8_COPY_REFERENCE, &stream->ref_enc);
/* Get the internal reference frame */
if (codec->fourcc == VP8_FOURCC) {
struct vpx_ref_frame ref_enc, ref_dec;
int width, height;
width = (stream->config.cfg.g_w + 15) & ~15;
height = (stream->config.cfg.g_h + 15) & ~15;
vpx_img_alloc(&ref_enc.img, VPX_IMG_FMT_I420, width, height, 1);
enc_img = ref_enc.img;
vpx_img_alloc(&ref_dec.img, VPX_IMG_FMT_I420, width, height, 1);
dec_img = ref_dec.img;
ref_enc.frame_type = VP8_LAST_FRAME;
ref_dec.frame_type = VP8_LAST_FRAME;
vpx_codec_control(&stream->encoder, VP8_COPY_REFERENCE, &ref_enc);
vpx_codec_control(&stream->decoder, VP8_COPY_REFERENCE, &ref_dec);
} else {
struct vp9_ref_frame ref;
ref.idx = 0;
vpx_codec_control(&stream->encoder, VP9_GET_REFERENCE, &ref);
enc_img = ref.img;
vpx_codec_control(&stream->decoder, VP9_GET_REFERENCE, &ref);
dec_img = ref.img;
}
ctx_exit_on_error(&stream->encoder, "Failed to get encoder reference frame");
vpx_codec_control(&stream->decoder, VP8_COPY_REFERENCE, &stream->ref_dec);
ctx_exit_on_error(&stream->decoder, "Failed to get decoder reference frame");
if (!compare_img(&stream->ref_enc.img, &stream->ref_dec.img)) {
if (!compare_img(&enc_img, &dec_img)) {
int y[2], u[2], v[2];
find_mismatch(&stream->ref_enc.img, &stream->ref_dec.img,
y, u, v);
find_mismatch(&enc_img, &dec_img, y, u, v);
stream->decoder.err = 1;
warn_or_exit_on_error(&stream->decoder, fatal == TEST_DECODE_FATAL,
"Stream %d: Encode/decode mismatch on frame %d"
@ -2450,6 +2464,9 @@ static void test_decode(struct stream_state *stream,
y[0], y[1], u[0], u[1], v[0], v[1]);
stream->mismatch_seen = stream->frames_out;
}
vpx_img_free(&enc_img);
vpx_img_free(&dec_img);
}
@ -2671,7 +2688,7 @@ int main(int argc, const char **argv_) {
}
if (got_data && global.test_decode != TEST_DECODE_OFF)
FOREACH_STREAM(test_decode(stream, global.test_decode));
FOREACH_STREAM(test_decode(stream, global.test_decode, global.codec));
}
fflush(stdout);
@ -2703,8 +2720,6 @@ int main(int argc, const char **argv_) {
if (global.test_decode != TEST_DECODE_OFF) {
FOREACH_STREAM(vpx_codec_destroy(&stream->decoder));
FOREACH_STREAM(vpx_img_free(&stream->ref_enc.img));
FOREACH_STREAM(vpx_img_free(&stream->ref_dec.img));
}
close_input_file(&input);