Commit 9aaa3c93 authored by Yunqing Wang's avatar Yunqing Wang

Make set_reference control API work in VP9 and VP10

Moved the API patch from NextGen to NextGenv2 and also added this
API to VP10. An example was included. To try it, for example, run
the following command:
$ examples/vpx_cx_set_ref vp10 352 288 in.yuv out.ivf 4 30

Change-Id: Ib56bc3d365e530cfc8d859a13ddbf4c007907b81
parent 916bdfd9
...@@ -204,6 +204,18 @@ vp8cx_set_ref.SRCS += vpx_ports/msvc.h ...@@ -204,6 +204,18 @@ vp8cx_set_ref.SRCS += vpx_ports/msvc.h
vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A vp8cx_set_ref.GUID = C5E31F7F-96F6-48BD-BD3E-10EBF6E8057A
vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame vp8cx_set_ref.DESCRIPTION = VP8 set encoder reference frame
# If vp9 is enabled, $(CONFIG_VP9_ENCODER) is yes, otherwise, it is blank.
ifneq (,$(filter yes,$(CONFIG_VP9_ENCODER) $(CONFIG_VP10_ENCODER)))
ifeq ($(CONFIG_DECODERS),yes)
EXAMPLES-yes += vpx_cx_set_ref.c
vpx_cx_set_ref.SRCS += ivfenc.h ivfenc.c
vpx_cx_set_ref.SRCS += tools_common.h tools_common.c
vpx_cx_set_ref.SRCS += video_common.h
vpx_cx_set_ref.SRCS += video_writer.h video_writer.c
vpx_cx_set_ref.GUID = 65D7F14A-2EE6-4293-B958-AB5107A03B55
vpx_cx_set_ref.DESCRIPTION = VP9/VP10 set encoder reference frame
endif
endif
ifeq ($(CONFIG_MULTI_RES_ENCODING),yes) ifeq ($(CONFIG_MULTI_RES_ENCODING),yes)
ifeq ($(CONFIG_LIBYUV),yes) ifeq ($(CONFIG_LIBYUV),yes)
......
This diff is collapsed.
...@@ -8,30 +8,27 @@ ...@@ -8,30 +8,27 @@
## in the file PATENTS. All contributing project authors may ## in the file PATENTS. All contributing project authors may
## 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.
## ##
## This file tests the libvpx vp8cx_set_ref example. To add new tests to this ## This file tests the libvpx cx_set_ref example. To add new tests to this
## file, do the following: ## file, do the following:
## 1. Write a shell function (this is your test). ## 1. Write a shell function (this is your test).
## 2. Add the function to vp8cx_set_ref_tests (on a new line). ## 2. Add the function to cx_set_ref_tests (on a new line).
## ##
. $(dirname $0)/tools_common.sh . $(dirname $0)/tools_common.sh
# Environment check: $YUV_RAW_INPUT is required. # Environment check: $YUV_RAW_INPUT is required.
vp8cx_set_ref_verify_environment() { cx_set_ref_verify_environment() {
if [ ! -e "${YUV_RAW_INPUT}" ]; then if [ ! -e "${YUV_RAW_INPUT}" ]; then
echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH." echo "Libvpx test data must exist in LIBVPX_TEST_DATA_PATH."
return 1 return 1
fi fi
} }
# Runs vp8cx_set_ref and updates the reference frame before encoding frame 90. # Runs cx_set_ref and updates the reference frame before encoding frame 90.
# $1 is the codec name, which vp8cx_set_ref does not support at present: It's # $1 is the codec name.
# currently used only to name the output file.
# TODO(tomfinegan): Pass the codec param once the example is updated to support
# VP9.
vpx_set_ref() { vpx_set_ref() {
local encoder="${LIBVPX_BIN_PATH}/vp8cx_set_ref${VPX_TEST_EXE_SUFFIX}"
local codec="$1" local codec="$1"
local output_file="${VPX_TEST_OUTPUT_DIR}/vp8cx_set_ref_${codec}.ivf" local encoder="${LIBVPX_BIN_PATH}/${codec}cx_set_ref${VPX_TEST_EXE_SUFFIX}"
local output_file="${VPX_TEST_OUTPUT_DIR}/${codec}cx_set_ref_${codec}.ivf"
local ref_frame_num=90 local ref_frame_num=90
if [ ! -x "${encoder}" ]; then if [ ! -x "${encoder}" ]; then
...@@ -46,12 +43,24 @@ vpx_set_ref() { ...@@ -46,12 +43,24 @@ vpx_set_ref() {
[ -e "${output_file}" ] || return 1 [ -e "${output_file}" ] || return 1
} }
vp8cx_set_ref_vp8() { cx_set_ref_vp8() {
if [ "$(vp8_encode_available)" = "yes" ]; then if [ "$(vp8_encode_available)" = "yes" ]; then
vpx_set_ref vp8 || return 1 vpx_set_ref vp8 || return 1
fi fi
} }
vp8cx_set_ref_tests="vp8cx_set_ref_vp8" cx_set_ref_vp9() {
if [ "$(vp9_encode_available)" = "yes" ]; then
vpx_set_ref vp9 || return 1
fi
}
cx_set_ref_vp10() {
if [ "$(vp10_encode_available)" = "yes" ]; then
vpx_set_ref vp10 || return 1
fi
}
cx_set_ref_tests="cx_set_ref_vp8 cx_set_ref_vp9 cx_set_ref_vp10"
run_tests vp8cx_set_ref_verify_environment "${vp8cx_set_ref_tests}" run_tests cx_set_ref_verify_environment "${cx_set_ref_tests}"
...@@ -197,31 +197,44 @@ vpx_codec_err_t vp10_copy_reference_dec(VP10Decoder *pbi, ...@@ -197,31 +197,44 @@ vpx_codec_err_t vp10_copy_reference_dec(VP10Decoder *pbi,
vpx_codec_err_t vp10_set_reference_dec(VP10_COMMON *cm, vpx_codec_err_t vp10_set_reference_dec(VP10_COMMON *cm,
VP9_REFFRAME ref_frame_flag, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) { YV12_BUFFER_CONFIG *sd) {
RefBuffer *ref_buf = NULL; int idx;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; YV12_BUFFER_CONFIG *ref_buf = NULL;
// TODO(jkoleszar): The decoder doesn't have any real knowledge of what the // TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
// encoder is using the frame buffers for. This is just a stub to keep the // encoder is using the frame buffers for. This is just a stub to keep the
// vpxenc --test-decode functionality working, and will be replaced in a // vpxenc --test-decode functionality working, and will be replaced in a
// later commit that adds VP9-specific controls for this functionality. // later commit that adds VP9-specific controls for this functionality.
// (Yunqing) The set_reference control depends on the following setting in
// encoder.
// cpi->lst_fb_idx = 0;
// #if CONFIG_EXT_REFS
// cpi->lst2_fb_idx = 1;
// cpi->lst3_fb_idx = 2;
// cpi->lst4_fb_idx = 3;
// cpi->gld_fb_idx = 4;
// cpi->alt_fb_idx = 5;
// #else // CONFIG_EXT_REFS
// cpi->gld_fb_idx = 1;
// cpi->alt_fb_idx = 2;
if (ref_frame_flag == VP9_LAST_FLAG) { if (ref_frame_flag == VP9_LAST_FLAG) {
ref_buf = &cm->frame_refs[0]; idx = cm->ref_frame_map[0];
#if CONFIG_EXT_REFS #if CONFIG_EXT_REFS
} else if (ref_frame_flag == VP9_LAST2_FLAG) { } else if (ref_frame_flag == VP9_LAST2_FLAG) {
ref_buf = &cm->frame_refs[1]; idx = cm->ref_frame_map[1];
} else if (ref_frame_flag == VP9_LAST3_FLAG) { } else if (ref_frame_flag == VP9_LAST3_FLAG) {
ref_buf = &cm->frame_refs[2]; idx = cm->ref_frame_map[2];
} else if (ref_frame_flag == VP9_LAST4_FLAG) { } else if (ref_frame_flag == VP9_LAST4_FLAG) {
ref_buf = &cm->frame_refs[3]; idx = cm->ref_frame_map[3];
} else if (ref_frame_flag == VP9_GOLD_FLAG) { } else if (ref_frame_flag == VP9_GOLD_FLAG) {
ref_buf = &cm->frame_refs[4]; idx = cm->ref_frame_map[4];
} else if (ref_frame_flag == VP9_ALT_FLAG) { } else if (ref_frame_flag == VP9_ALT_FLAG) {
ref_buf = &cm->frame_refs[5]; idx = cm->ref_frame_map[5];
#else #else
} else if (ref_frame_flag == VP9_GOLD_FLAG) { } else if (ref_frame_flag == VP9_GOLD_FLAG) {
ref_buf = &cm->frame_refs[1]; idx = cm->ref_frame_map[1];
} else if (ref_frame_flag == VP9_ALT_FLAG) { } else if (ref_frame_flag == VP9_ALT_FLAG) {
ref_buf = &cm->frame_refs[2]; idx = cm->ref_frame_map[2];
#endif // CONFIG_EXT_REFS #endif // CONFIG_EXT_REFS
} else { } else {
vpx_internal_error(&cm->error, VPX_CODEC_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
...@@ -229,25 +242,21 @@ vpx_codec_err_t vp10_set_reference_dec(VP10_COMMON *cm, ...@@ -229,25 +242,21 @@ vpx_codec_err_t vp10_set_reference_dec(VP10_COMMON *cm,
return cm->error.error_code; return cm->error.error_code;
} }
if (!equal_dimensions(ref_buf->buf, sd)) { if (idx < 0 || idx >= FRAME_BUFFERS) {
vpx_internal_error(&cm->error, VPX_CODEC_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
"Incorrect buffer dimensions"); "Invalid reference frame map");
} else { return cm->error.error_code;
int *ref_fb_ptr = &ref_buf->idx; }
// Find an empty frame buffer.
const int free_fb = get_free_fb(cm);
if (cm->new_fb_idx == INVALID_IDX)
return VPX_CODEC_MEM_ERROR;
// Decrease ref_count since it will be increased again in // Get the destination reference buffer.
// ref_cnt_fb() below. ref_buf = &cm->buffer_pool->frame_bufs[idx].buf;
--frame_bufs[free_fb].ref_count;
// Manage the reference counters and copy image. if (!equal_dimensions(ref_buf, sd)) {
ref_cnt_fb(frame_bufs, ref_fb_ptr, free_fb); vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
ref_buf->buf = &frame_bufs[*ref_fb_ptr].buf; "Incorrect buffer dimensions");
vp8_yv12_copy_frame(sd, ref_buf->buf); } else {
// Overwrite the reference frame buffer.
vp8_yv12_copy_frame(sd, ref_buf);
} }
return cm->error.error_code; return cm->error.error_code;
......
...@@ -107,19 +107,6 @@ struct vpx_codec_alg_priv { ...@@ -107,19 +107,6 @@ struct vpx_codec_alg_priv {
BufferPool *buffer_pool; BufferPool *buffer_pool;
}; };
static VP9_REFFRAME ref_frame_to_vp10_reframe(vpx_ref_frame_type_t frame) {
switch (frame) {
case VP8_LAST_FRAME:
return VP9_LAST_FLAG;
case VP8_GOLD_FRAME:
return VP9_GOLD_FLAG;
case VP8_ALTR_FRAME:
return VP9_ALT_FLAG;
}
assert(0 && "Invalid Reference Frame");
return VP9_LAST_FLAG;
}
static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx, static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx,
const struct vpx_internal_error_info *error) { const struct vpx_internal_error_info *error) {
const vpx_codec_err_t res = error->error_code; const vpx_codec_err_t res = error->error_code;
......
...@@ -866,7 +866,8 @@ static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx, ...@@ -866,7 +866,8 @@ static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
image2yuvconfig(&frame->img, &sd); image2yuvconfig(&frame->img, &sd);
return vp10_set_reference_dec(&frame_worker_data->pbi->common, return vp10_set_reference_dec(&frame_worker_data->pbi->common,
(VP9_REFFRAME)frame->frame_type, &sd); ref_frame_to_vp10_reframe(frame->frame_type),
&sd);
} else { } else {
return VPX_CODEC_INVALID_PARAM; return VPX_CODEC_INVALID_PARAM;
} }
......
...@@ -133,4 +133,16 @@ static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, ...@@ -133,4 +133,16 @@ static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img,
return VPX_CODEC_OK; return VPX_CODEC_OK;
} }
static VP9_REFFRAME ref_frame_to_vp10_reframe(vpx_ref_frame_type_t frame) {
switch (frame) {
case VP8_LAST_FRAME:
return VP9_LAST_FLAG;
case VP8_GOLD_FRAME:
return VP9_GOLD_FLAG;
case VP8_ALTR_FRAME:
return VP9_ALT_FLAG;
}
assert(0 && "Invalid Reference Frame");
return VP9_LAST_FLAG;
}
#endif // VP10_VP10_IFACE_COMMON_H_ #endif // VP10_VP10_IFACE_COMMON_H_
...@@ -186,44 +186,46 @@ vpx_codec_err_t vp9_copy_reference_dec(VP9Decoder *pbi, ...@@ -186,44 +186,46 @@ vpx_codec_err_t vp9_copy_reference_dec(VP9Decoder *pbi,
vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm, vpx_codec_err_t vp9_set_reference_dec(VP9_COMMON *cm,
VP9_REFFRAME ref_frame_flag, VP9_REFFRAME ref_frame_flag,
YV12_BUFFER_CONFIG *sd) { YV12_BUFFER_CONFIG *sd) {
RefBuffer *ref_buf = NULL; int idx;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs; YV12_BUFFER_CONFIG *ref_buf = NULL;
// TODO(jkoleszar): The decoder doesn't have any real knowledge of what the // TODO(jkoleszar): The decoder doesn't have any real knowledge of what the
// encoder is using the frame buffers for. This is just a stub to keep the // encoder is using the frame buffers for. This is just a stub to keep the
// vpxenc --test-decode functionality working, and will be replaced in a // vpxenc --test-decode functionality working, and will be replaced in a
// later commit that adds VP9-specific controls for this functionality. // later commit that adds VP9-specific controls for this functionality.
// (Yunqing) The set_reference control depends on the following setting in
// encoder.
// cpi->lst_fb_idx = 0;
// cpi->gld_fb_idx = 1;
// cpi->alt_fb_idx = 2;
if (ref_frame_flag == VP9_LAST_FLAG) { if (ref_frame_flag == VP9_LAST_FLAG) {
ref_buf = &cm->frame_refs[0]; idx = cm->ref_frame_map[0];
} else if (ref_frame_flag == VP9_GOLD_FLAG) { } else if (ref_frame_flag == VP9_GOLD_FLAG) {
ref_buf = &cm->frame_refs[1]; idx = cm->ref_frame_map[1];
} else if (ref_frame_flag == VP9_ALT_FLAG) { } else if (ref_frame_flag == VP9_ALT_FLAG) {
ref_buf = &cm->frame_refs[2]; idx = cm->ref_frame_map[2];
} else { } else {
vpx_internal_error(&cm->error, VPX_CODEC_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
"Invalid reference frame"); "Invalid reference frame");
return cm->error.error_code; return cm->error.error_code;
} }
if (!equal_dimensions(ref_buf->buf, sd)) { if (idx < 0 || idx >= FRAME_BUFFERS) {
vpx_internal_error(&cm->error, VPX_CODEC_ERROR, vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
"Incorrect buffer dimensions"); "Invalid reference frame map");
} else { return cm->error.error_code;
int *ref_fb_ptr = &ref_buf->idx; }
// Find an empty frame buffer.
const int free_fb = get_free_fb(cm);
if (cm->new_fb_idx == INVALID_IDX)
return VPX_CODEC_MEM_ERROR;
// Decrease ref_count since it will be increased again in // Get the destination reference buffer.
// ref_cnt_fb() below. ref_buf = &cm->buffer_pool->frame_bufs[idx].buf;
--frame_bufs[free_fb].ref_count;
// Manage the reference counters and copy image. if (!equal_dimensions(ref_buf, sd)) {
ref_cnt_fb(frame_bufs, ref_fb_ptr, free_fb); vpx_internal_error(&cm->error, VPX_CODEC_ERROR,
ref_buf->buf = &frame_bufs[*ref_fb_ptr].buf; "Incorrect buffer dimensions");
vp8_yv12_copy_frame(sd, ref_buf->buf); } else {
// Overwrite the reference frame buffer.
vp8_yv12_copy_frame(sd, ref_buf);
} }
return cm->error.error_code; return cm->error.error_code;
......
...@@ -103,19 +103,6 @@ struct vpx_codec_alg_priv { ...@@ -103,19 +103,6 @@ struct vpx_codec_alg_priv {
BufferPool *buffer_pool; BufferPool *buffer_pool;
}; };
static VP9_REFFRAME ref_frame_to_vp9_reframe(vpx_ref_frame_type_t frame) {
switch (frame) {
case VP8_LAST_FRAME:
return VP9_LAST_FLAG;
case VP8_GOLD_FRAME:
return VP9_GOLD_FLAG;
case VP8_ALTR_FRAME:
return VP9_ALT_FLAG;
}
assert(0 && "Invalid Reference Frame");
return VP9_LAST_FLAG;
}
static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx, static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx,
const struct vpx_internal_error_info *error) { const struct vpx_internal_error_info *error) {
const vpx_codec_err_t res = error->error_code; const vpx_codec_err_t res = error->error_code;
......
...@@ -776,7 +776,8 @@ static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx, ...@@ -776,7 +776,8 @@ static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1; FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
image2yuvconfig(&frame->img, &sd); image2yuvconfig(&frame->img, &sd);
return vp9_set_reference_dec(&frame_worker_data->pbi->common, return vp9_set_reference_dec(&frame_worker_data->pbi->common,
(VP9_REFFRAME)frame->frame_type, &sd); ref_frame_to_vp9_reframe(frame->frame_type),
&sd);
} else { } else {
return VPX_CODEC_INVALID_PARAM; return VPX_CODEC_INVALID_PARAM;
} }
......
...@@ -133,4 +133,16 @@ static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, ...@@ -133,4 +133,16 @@ static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img,
return VPX_CODEC_OK; return VPX_CODEC_OK;
} }
static VP9_REFFRAME ref_frame_to_vp9_reframe(vpx_ref_frame_type_t frame) {
switch (frame) {
case VP8_LAST_FRAME:
return VP9_LAST_FLAG;
case VP8_GOLD_FRAME:
return VP9_GOLD_FLAG;
case VP8_ALTR_FRAME:
return VP9_ALT_FLAG;
}
assert(0 && "Invalid Reference Frame");
return VP9_LAST_FLAG;
}
#endif // VP9_VP9_IFACE_COMMON_H_ #endif // VP9_VP9_IFACE_COMMON_H_
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