Commit 1ed0e1be authored by Ivan Maltz's avatar Ivan Maltz

Move SVC per-frame loop from sample app into libvpx proper

SVC multiple layer per frame encoding is invoked with vpx_svc_init and
vpx_svc_encode. These interfaces are designed to be invoked from ffmpeg.
Additional improvements:
- make dummy frame handling a bit more explicit
- fixed bug with single layer encodes
- track individual frame sizes and psnrs instead of averages
- parameterized quantizer, 16th scalefactors, more logging,
- enabled single layer encodes to generate baseline
- include new mode for 3 layer I frame with 5 total layers

Change-Id: I46cfa600d102e208c6af8acd6132e0cc25cda8d4
parent 9cc4935d
......@@ -50,6 +50,7 @@ UTILS-$(CONFIG_VP8_ENCODER) += vp8_scalable_patterns.c
vp8_scalable_patterns.GUID = 0D6A210B-F482-4D6F-8570-4A9C01ACC88C
vp8_scalable_patterns.DESCRIPTION = Temporal Scalability Encoder
UTILS-$(CONFIG_VP9_ENCODER) += vp9_spatial_scalable_encoder.c
vp9_spatial_scalable_encoder.SRCS += args.c args.h
vp9_spatial_scalable_encoder.GUID = 4A38598D-627D-4505-9C7B-D4020C84100D
vp9_spatial_scalable_encoder.DESCRIPTION = Spatial Scalable Encoder
......
......@@ -122,6 +122,7 @@ ifeq ($(CONFIG_VP9_ENCODER),yes)
CODEC_EXPORTS-yes += $(addprefix $(VP9_PREFIX),$(VP9_CX_EXPORTS))
CODEC_SRCS-yes += $(VP9_PREFIX)vp9cx.mk vpx/vp8.h vpx/vp8cx.h
INSTALL-LIBS-yes += include/vpx/vp8.h include/vpx/vp8cx.h
INSTALL-LIBS-yes += include/vpx/svc_context.h
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/%
CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h
CODEC_DOC_SECTIONS += vp9 vp9_encoder
......
/*
* 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.
*/
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/i420_video_source.h"
#include "vpx/svc_context.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
namespace {
using libvpx_test::CodecFactory;
using libvpx_test::Decoder;
using libvpx_test::VP9CodecFactory;
class SvcTest : public ::testing::Test {
protected:
static const uint32_t kWidth = 352;
static const uint32_t kHeight = 288;
SvcTest()
: codec_iface_(0),
test_file_name_("hantro_collage_w352h288.yuv"),
decoder_(0) {}
virtual ~SvcTest() {}
virtual void SetUp() {
memset(&svc_, 0, sizeof(svc_));
svc_.first_frame_full_size = 1;
svc_.encoding_mode = INTER_LAYER_PREDICTION_IP;
svc_.log_level = SVC_LOG_DEBUG;
svc_.log_print = 0;
codec_iface_ = vpx_codec_vp9_cx();
const vpx_codec_err_t res =
vpx_codec_enc_config_default(codec_iface_, &codec_enc_, 0);
EXPECT_EQ(VPX_CODEC_OK, res);
codec_enc_.g_w = kWidth;
codec_enc_.g_h = kHeight;
codec_enc_.g_timebase.num = 1;
codec_enc_.g_timebase.den = 60;
codec_enc_.kf_min_dist = 100;
codec_enc_.kf_max_dist = 100;
vpx_codec_dec_cfg_t dec_cfg = {0};
VP9CodecFactory codec_factory;
decoder_ = codec_factory.CreateDecoder(dec_cfg, 0);
}
virtual void TearDown() {
vpx_svc_release(&svc_);
}
SvcContext svc_;
vpx_codec_ctx_t codec_;
struct vpx_codec_enc_cfg codec_enc_;
vpx_codec_iface_t *codec_iface_;
std::string test_file_name_;
Decoder *decoder_;
};
TEST_F(SvcTest, SvcInit) {
svc_.spatial_layers = 0; // use default layers
vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(VPX_SS_DEFAULT_LAYERS, svc_.spatial_layers);
res = vpx_svc_init(NULL, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_init(&svc_, NULL, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_init(&svc_, &codec_, NULL, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_init(&svc_, &codec_, codec_iface_, NULL);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
svc_.spatial_layers = 6; // too many layers
res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
svc_.spatial_layers = 2;
vpx_svc_set_scale_factors(&svc_, "4/16,16*16"); // invalid scale values
res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); // valid scale values
res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
}
TEST_F(SvcTest, SetOptions) {
vpx_codec_err_t res = vpx_svc_set_options(NULL, "layers=3");
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
vpx_svc_set_options(&svc_, NULL);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
vpx_svc_set_options(&svc_, "layers=3");
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(3, svc_.spatial_layers);
vpx_svc_set_options(&svc_, "not-an-option=1");
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
vpx_svc_set_options(&svc_, "encoding-mode=alt-ip");
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(ALT_INTER_LAYER_PREDICTION_IP, svc_.encoding_mode);
vpx_svc_set_options(&svc_, "layers=2 encoding-mode=ip");
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(2, svc_.spatial_layers);
EXPECT_EQ(INTER_LAYER_PREDICTION_IP, svc_.encoding_mode);
vpx_svc_set_options(&svc_, "scale-factors=not-scale-factors");
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3");
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
vpx_svc_set_options(&svc_, "quantizers=not-quantizers");
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
vpx_svc_set_options(&svc_, "quantizers=40,45");
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
}
TEST_F(SvcTest, SetQuantizers) {
vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,30");
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_quantizers(&svc_, NULL);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
svc_.first_frame_full_size = 0;
svc_.spatial_layers = 2;
res = vpx_svc_set_quantizers(&svc_, "40,30");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_set_quantizers(&svc_, "40");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
}
TEST_F(SvcTest, SetScaleFactors) {
vpx_codec_err_t res = vpx_svc_set_scale_factors(NULL, "4/16,16/16");
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_set_scale_factors(&svc_, NULL);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
svc_.first_frame_full_size = 0;
svc_.spatial_layers = 2;
res = vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_set_scale_factors(&svc_, "4/16");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
}
// test that decoder can handle an SVC frame as the first frame in a sequence
// this test is disabled since it always fails because of a decoder issue
// https://code.google.com/p/webm/issues/detail?id=654
TEST_F(SvcTest, DISABLED_FirstFrameHasLayers) {
svc_.first_frame_full_size = 0;
svc_.spatial_layers = 2;
vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
vpx_svc_set_quantizers(&svc_, "40,30");
vpx_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
codec_enc_.g_timebase.den,
codec_enc_.g_timebase.num, 0, 30);
video.Begin();
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_REALTIME);
EXPECT_EQ(VPX_CODEC_OK, res);
const vpx_codec_err_t res_dec = decoder_->DecodeFrame(
static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
vpx_svc_get_frame_size(&svc_));
// this test fails with a decoder error
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
}
TEST_F(SvcTest, EncodeThreeFrames) {
svc_.first_frame_full_size = 1;
svc_.spatial_layers = 2;
vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
vpx_svc_set_quantizers(&svc_, "40,30");
vpx_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
ASSERT_EQ(VPX_CODEC_OK, res);
libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
codec_enc_.g_timebase.den,
codec_enc_.g_timebase.num, 0, 30);
// FRAME 1
video.Begin();
// this frame is full size, with only one layer
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_REALTIME);
ASSERT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
vpx_codec_err_t res_dec = decoder_->DecodeFrame(
static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
vpx_svc_get_frame_size(&svc_));
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
// FRAME 2
video.Next();
// this is an I-frame
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_REALTIME);
ASSERT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
res_dec = decoder_->DecodeFrame(
static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
vpx_svc_get_frame_size(&svc_));
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
// FRAME 2
video.Next();
// this is a P-frame
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_REALTIME);
ASSERT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
res_dec = decoder_->DecodeFrame(
static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
vpx_svc_get_frame_size(&svc_));
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
}
TEST_F(SvcTest, GetLayerResolution) {
svc_.first_frame_full_size = 0;
svc_.spatial_layers = 2;
vpx_svc_set_scale_factors(&svc_, "4/16,8/16");
vpx_svc_set_quantizers(&svc_, "40,30");
vpx_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_OK, res);
// ensure that requested layer is a valid layer
uint32_t layer_width, layer_height;
res = vpx_svc_get_layer_resolution(&svc_, svc_.spatial_layers,
&layer_width, &layer_height);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_get_layer_resolution(NULL, 0, &layer_width, &layer_height);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_get_layer_resolution(&svc_, 0, NULL, &layer_height);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, NULL);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, &layer_height);
EXPECT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(kWidth * 4 / 16, layer_width);
EXPECT_EQ(kHeight * 4 / 16, layer_height);
res = vpx_svc_get_layer_resolution(&svc_, 1, &layer_width, &layer_height);
EXPECT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(kWidth * 8 / 16, layer_width);
EXPECT_EQ(kHeight * 8 / 16, layer_height);
}
} // namespace
......@@ -96,6 +96,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += fdct8x8_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct16x16_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += variance_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += dct32x32_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += svc_test.cc
endif # VP9
......
......@@ -221,8 +221,6 @@ extern "C"
int vp9_set_size_literal(VP9_PTR comp, unsigned int width,
unsigned int height);
int vp9_switch_layer(VP9_PTR comp, int layer);
void vp9_set_svc(VP9_PTR comp, int use_svc);
int vp9_get_quantizer(VP9_PTR c);
......
......@@ -4224,37 +4224,9 @@ int vp9_set_size_literal(VP9_PTR comp, unsigned int width,
return 0;
}
int vp9_switch_layer(VP9_PTR comp, int layer) {
VP9_COMP *cpi = (VP9_COMP *)comp;
if (cpi->use_svc) {
cpi->current_layer = layer;
// Use buffer i for layer i LST
cpi->lst_fb_idx = layer;
// Use buffer i-1 for layer i Alt (Inter-layer prediction)
if (layer != 0) cpi->alt_fb_idx = layer - 1;
// Use the rest for Golden
if (layer < 2 * cpi->number_spatial_layers - NUM_REF_FRAMES)
cpi->gld_fb_idx = cpi->lst_fb_idx;
else
cpi->gld_fb_idx = 2 * cpi->number_spatial_layers - 1 - layer;
printf("Switching to layer %d:\n", layer);
printf("Using references: LST/GLD/ALT [%d|%d|%d]\n", cpi->lst_fb_idx,
cpi->gld_fb_idx, cpi->alt_fb_idx);
} else {
printf("Switching layer not supported. Enable SVC first \n");
}
return 0;
}
void vp9_set_svc(VP9_PTR comp, int use_svc) {
VP9_COMP *cpi = (VP9_COMP *)comp;
cpi->use_svc = use_svc;
if (cpi->use_svc) printf("Enabled SVC encoder \n");
return;
}
......
......@@ -442,8 +442,6 @@ static vpx_codec_err_t set_param(vpx_codec_alg_priv_t *ctx,
MAP(VP8E_SET_ARNR_TYPE, xcfg.arnr_type);
MAP(VP8E_SET_TUNING, xcfg.tuning);
MAP(VP8E_SET_CQ_LEVEL, xcfg.cq_level);
MAP(VP9E_SET_MAX_Q, ctx->cfg.rc_max_quantizer);
MAP(VP9E_SET_MIN_Q, ctx->cfg.rc_min_quantizer);
MAP(VP8E_SET_MAX_INTRA_BITRATE_PCT, xcfg.rc_max_intra_bitrate_pct);
MAP(VP9E_SET_LOSSLESS, xcfg.lossless);
MAP(VP9E_SET_FRAME_PARALLEL_DECODING, xcfg.frame_parallel_decoding_mode);
......@@ -1029,66 +1027,40 @@ static vpx_codec_err_t vp9e_set_scalemode(vpx_codec_alg_priv_t *ctx,
}
}
static vpx_codec_err_t vp9e_set_width(vpx_codec_alg_priv_t *ctx, int ctr_id,
va_list args) {
unsigned int *data = va_arg(args, unsigned int *);
if (data) {
int res;
res = vp9_set_size_literal(ctx->cpi, *data, 0);
if (!res) {
return VPX_CODEC_OK;
} else {
return VPX_CODEC_INVALID_PARAM;
}
} else {
return VPX_CODEC_INVALID_PARAM;
}
static vpx_codec_err_t vp9e_set_svc(vpx_codec_alg_priv_t *ctx, int ctr_id,
va_list args) {
int data = va_arg(args, int);
vp9_set_svc(ctx->cpi, data);
return VPX_CODEC_OK;
}
static vpx_codec_err_t vp9e_set_height(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
unsigned int *data = va_arg(args, unsigned int *);
if (data) {
int res;
res = vp9_set_size_literal(ctx->cpi, 0, *data);
static vpx_codec_err_t vp9e_set_svc_parameters(vpx_codec_alg_priv_t *ctx,
int ctr_id, va_list args) {
vpx_svc_parameters_t *data = va_arg(args, vpx_svc_parameters_t *);
VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
vpx_svc_parameters_t params;
if (!res) {
return VPX_CODEC_OK;
} else {
return VPX_CODEC_INVALID_PARAM;
}
} else {
if (data == NULL) {
return VPX_CODEC_INVALID_PARAM;
}
}
static vpx_codec_err_t vp9e_set_layer(vpx_codec_alg_priv_t *ctx,
int ctr_id,
va_list args) {
unsigned int *data = va_arg(args, unsigned int *);
if (data) {
int res;
res = 0;
params = *(vpx_svc_parameters_t *)data;
res = vp9_switch_layer(ctx->cpi, *data);
cpi->current_layer = params.layer;
cpi->lst_fb_idx = params.lst_fb_idx;
cpi->gld_fb_idx = params.gld_fb_idx;
cpi->alt_fb_idx = params.alt_fb_idx;
if (!res) {
return VPX_CODEC_OK;
} else {
return VPX_CODEC_INVALID_PARAM;
}
} else {
if (vp9_set_size_literal(ctx->cpi, params.width, params.height) != 0) {
return VPX_CODEC_INVALID_PARAM;
}
}
static vpx_codec_err_t vp9e_set_svc(vpx_codec_alg_priv_t *ctx, int ctr_id,
va_list args) {
int data = va_arg(args, int);
vp9_set_svc(ctx->cpi, data);
ctx->cfg.rc_max_quantizer = params.max_quantizer;
ctx->cfg.rc_min_quantizer = params.min_quantizer;
set_vp9e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg);
vp9_change_config(ctx->cpi, &ctx->oxcf);
return VPX_CODEC_OK;
}
......@@ -1116,16 +1088,12 @@ static vpx_codec_ctrl_fn_map_t vp9e_ctf_maps[] = {
{VP8E_SET_ARNR_TYPE, set_param},
{VP8E_SET_TUNING, set_param},
{VP8E_SET_CQ_LEVEL, set_param},
{VP9E_SET_MAX_Q, set_param},
{VP9E_SET_MIN_Q, set_param},
{VP8E_SET_MAX_INTRA_BITRATE_PCT, set_param},
{VP9E_SET_LOSSLESS, set_param},
{VP9E_SET_FRAME_PARALLEL_DECODING, set_param},
{VP9_GET_REFERENCE, get_reference},
{VP9E_SET_WIDTH, vp9e_set_width},
{VP9E_SET_HEIGHT, vp9e_set_height},
{VP9E_SET_LAYER, vp9e_set_layer},
{VP9E_SET_SVC, vp9e_set_svc},
{VP9E_SET_SVC_PARAMETERS, vp9e_set_svc_parameters},
{ -1, NULL},
};
......
This diff is collapsed.
......@@ -6,3 +6,17 @@ text vpx_codec_get_cx_data
text vpx_codec_get_global_headers
text vpx_codec_get_preview_frame
text vpx_codec_set_cx_data_buf
text vpx_svc_dump_statistics
text vpx_svc_encode
text vpx_svc_free
text vpx_svc_get_buffer
text vpx_svc_get_encode_frame_count
text vpx_svc_get_frame_size
text vpx_svc_get_message
text vpx_svc_init
text vpx_svc_is_keyframe
text vpx_svc_release
text vpx_svc_set_keyframe
text vpx_svc_set_options
text vpx_svc_set_quantizers
text vpx_svc_set_scale_factors
This diff is collapsed.
/*
* 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.
*/
/**
* SvcContext - input parameters and state to encode a multi-layered
* spatial SVC frame
*/
#ifndef VPX_SVC_CONTEXT_H_
#define VPX_SVC_CONTEXT_H_
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum SVC_ENCODING_MODE {
INTER_LAYER_PREDICTION_I,
ALT_INTER_LAYER_PREDICTION_IP,
INTER_LAYER_PREDICTION_IP,
USE_GOLDEN_FRAME
} SVC_ENCODING_MODE;
typedef enum SVC_LOG_LEVEL {
SVC_LOG_ERROR,
SVC_LOG_INFO,
SVC_LOG_DEBUG
} SVC_LOG_LEVEL;
typedef struct {
// public interface to svc_command options
int spatial_layers; // number of layers
int first_frame_full_size; // set to one to force first frame full size
SVC_ENCODING_MODE encoding_mode; // svc encoding strategy
SVC_LOG_LEVEL log_level; // amount of information to display
int log_print; // when set, printf log messages instead of returning the
// message with svc_get_message
// private storage for vpx_svc_encode
void *internal;
} SvcContext;
/**
* Set SVC options
* options are supplied as a single string separated by spaces
* Format: encoding-mode=<i|ip|alt-ip|gf>
* layers=<layer_count>
* scaling-factors=<n1>/<d1>,<n2>/<d2>,...
* quantizers=<q1>,<q2>,...
*/
vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options);
/**
* Set SVC quantizer values
* values comma separated, ordered from lowest resolution to highest
* e.g., "60,53,39,33,27"
*/
vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx,
const char *quantizer_values);
/**
* Set SVC scale factors
* values comma separated, ordered from lowest resolution to highest
* e.g., "4/16,5/16,7/16,11/16,16/16"
*/
vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx,
const char *scale_factors);
/**
* initialize SVC encoding
*/
vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
vpx_codec_iface_t *iface,
vpx_codec_enc_cfg_t *cfg);
/**
* encode a frame of video with multiple layers
*/
vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
struct vpx_image *rawimg, vpx_codec_pts_t pts,
int64_t duration, int deadline);
/**
* finished with svc encoding, release allocated resources
*/
void vpx_svc_release(SvcContext *svc_ctx);
/**
* dump accumulated statistics and reset accumulated values
*/
const char *vpx_svc_dump_statistics(SvcContext *svc_ctx);
/**
* get status message from previous encode
*/
const char *vpx_svc_get_message(const SvcContext *svc_ctx);
/**
* return size of encoded data to be returned by vpx_svc_get_buffer
*/
size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx);
/**
* return buffer with encoded data
*/
void *vpx_svc_get_buffer(const SvcContext *svc_ctx);
/**