ea8aaf15b5
This patch only works if the video is a width and height that are both a multiple of 32.. It sets every partition to 16x16, and does INTRADC only on the first frame and ZEROMV on every other frame. It always does does the largest possible transform, and loop filter level is set to 4. Was ~20% faster than speed -5 of vp8 Now 20% slower but adds motion search ( every block ), nearest, near and zeromv The SVC test was changed because - while this realtime mode produces bad quality albeit quickly, it isn't obeying all the rules it should about which frames are available. Change-Id: I235c0b22573957986d41497dfb84568ec1dec8c7
338 lines
11 KiB
C++
338 lines
11 KiB
C++
/*
|
|
* 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"),
|
|
codec_initialized_(false),
|
|
decoder_(0) {
|
|
memset(&svc_, 0, sizeof(svc_));
|
|
memset(&codec_, 0, sizeof(codec_));
|
|
memset(&codec_enc_, 0, sizeof(codec_enc_));
|
|
}
|
|
|
|
virtual ~SvcTest() {}
|
|
|
|
virtual void SetUp() {
|
|
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_);
|
|
delete(decoder_);
|
|
if (codec_initialized_) vpx_codec_destroy(&codec_);
|
|
}
|
|
|
|
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_;
|
|
bool codec_initialized_;
|
|
Decoder *decoder_;
|
|
};
|
|
|
|
TEST_F(SvcTest, SvcInit) {
|
|
// test missing parameters
|
|
vpx_codec_err_t 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 = 0; // use default layers
|
|
res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
|
|
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
codec_initialized_ = true;
|
|
EXPECT_EQ(VPX_SS_DEFAULT_LAYERS, svc_.spatial_layers);
|
|
}
|
|
|
|
TEST_F(SvcTest, InitTwoLayers) {
|
|
svc_.spatial_layers = 2;
|
|
vpx_svc_set_scale_factors(&svc_, "4/16,16*16"); // invalid scale values
|
|
vpx_codec_err_t 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);
|
|
codec_initialized_ = true;
|
|
}
|
|
|
|
TEST_F(SvcTest, InvalidOptions) {
|
|
vpx_codec_err_t res = vpx_svc_set_options(&svc_, NULL);
|
|
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
|
|
|
|
res = vpx_svc_set_options(&svc_, "not-an-option=1");
|
|
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, SetLayersOption) {
|
|
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "layers=3");
|
|
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
|
|
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
codec_initialized_ = true;
|
|
EXPECT_EQ(3, svc_.spatial_layers);
|
|
}
|
|
|
|
TEST_F(SvcTest, SetEncodingMode) {
|
|
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "encoding-mode=alt-ip");
|
|
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
|
|
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
codec_initialized_ = true;
|
|
EXPECT_EQ(ALT_INTER_LAYER_PREDICTION_IP, svc_.encoding_mode);
|
|
}
|
|
|
|
TEST_F(SvcTest, SetMultipleOptions) {
|
|
vpx_codec_err_t res = 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);
|
|
codec_initialized_ = true;
|
|
EXPECT_EQ(2, svc_.spatial_layers);
|
|
EXPECT_EQ(INTER_LAYER_PREDICTION_IP, svc_.encoding_mode);
|
|
}
|
|
|
|
TEST_F(SvcTest, SetScaleFactorsOption) {
|
|
svc_.spatial_layers = 2;
|
|
vpx_codec_err_t res =
|
|
vpx_svc_set_options(&svc_, "scale-factors=not-scale-factors");
|
|
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);
|
|
|
|
res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3");
|
|
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
|
|
EXPECT_EQ(VPX_CODEC_OK, res);
|
|
codec_initialized_ = true;
|
|
}
|
|
|
|
TEST_F(SvcTest, SetQuantizersOption) {
|
|
svc_.spatial_layers = 2;
|
|
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "quantizers=not-quantizers");
|
|
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);
|
|
|
|
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);
|
|
codec_initialized_ = true;
|
|
}
|
|
|
|
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_.spatial_layers = 2;
|
|
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);
|
|
|
|
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);
|
|
codec_initialized_ = true;
|
|
}
|
|
|
|
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_.spatial_layers = 2;
|
|
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);
|
|
|
|
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);
|
|
codec_initialized_ = true;
|
|
}
|
|
|
|
// Test that decoder can handle an SVC frame as the first frame in a sequence.
|
|
TEST_F(SvcTest, FirstFrameHasLayers) {
|
|
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);
|
|
codec_initialized_ = true;
|
|
|
|
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_GOOD_QUALITY);
|
|
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_.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);
|
|
codec_initialized_ = true;
|
|
|
|
libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
|
|
codec_enc_.g_timebase.den,
|
|
codec_enc_.g_timebase.num, 0, 30);
|
|
// FRAME 0
|
|
video.Begin();
|
|
// This frame is a keyframe.
|
|
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
|
|
video.duration(), VPX_DL_GOOD_QUALITY);
|
|
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 1
|
|
video.Next();
|
|
// This is a P-frame.
|
|
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
|
|
video.duration(), VPX_DL_GOOD_QUALITY);
|
|
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();
|
|
|
|
// FRAME 2
|
|
video.Next();
|
|
// This is a P-frame.
|
|
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
|
|
video.duration(), VPX_DL_GOOD_QUALITY);
|
|
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_.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);
|
|
codec_initialized_ = true;
|
|
|
|
// 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
|