shithub: libvpx

ref: 908a992d7fde8218139c0ad298d8a60cc66650b6
dir: /test/svc_test.cc/

View raw version
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/i420_video_source.h"
#include "test/decode_test_driver.h"
#include "vpx/vpx_encoder.h"
#include "vpx/vp8cx.h"
#include "test/codec_factory.h"

extern "C" {
#include "vpx/svc_context.h"
}

namespace {

using libvpx_test::CodecFactory;
using libvpx_test::VP9CodecFactory;
using libvpx_test::Decoder;

class SvcTest : public ::testing::Test {
 protected:
  SvcTest()
      : codec_iface_(0),
        test_file_name("hantro_collage_w352h288.yuv"),
        decoder_(0) {}

  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 = 1;
    svc_.gop_size = 100;

    codec_iface_ = vpx_codec_vp9_cx();
    vpx_codec_err_t res =
        vpx_codec_enc_config_default(codec_iface_, &codec_enc_, 0);
    EXPECT_EQ(res, VPX_CODEC_OK);

    codec_enc_.g_w = kWidth;
    codec_enc_.g_h = kHeight;
    codec_enc_.g_timebase.num = 1;
    codec_enc_.g_timebase.den = 60;

    vpx_codec_dec_cfg_t dec_cfg = {0};
    VP9CodecFactory codec_factory;
    decoder_ = codec_factory.CreateDecoder(dec_cfg, 0);
  }

  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;
  enum {
    kWidth = 352,
    kHeight = 288,
  };

  Decoder* decoder_;
};

TEST_F(SvcTest, SvcInit) {
  svc_.spatial_layers = 0;  // not enough layers
  vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
  EXPECT_EQ(res, VPX_CODEC_INVALID_PARAM);

  svc_.spatial_layers = 6;  // too many layers
  res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
  EXPECT_EQ(res, VPX_CODEC_INVALID_PARAM);

  svc_.spatial_layers = 2;
  svc_.scale_factors = "4/16,16*16";  // invalid scale values
  res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
  EXPECT_EQ(res, VPX_CODEC_INVALID_PARAM);

  svc_.scale_factors = "4/16,16/16";  // valid scale values

  res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
  EXPECT_EQ(res, VPX_CODEC_OK);
}

// test that decoder can handle an svc frame as the first frame in a sequence
// this test is disabled since it with the deco
TEST_F(SvcTest, DISABLED_FirstFrameHasLayers) {
  svc_.first_frame_full_size = 0;
  svc_.spatial_layers = 2;
  svc_.scale_factors = "4/16,16/16";
  svc_.quantizer_values = "40,30";

  vpx_codec_err_t res =
      vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(res, VPX_CODEC_OK);

  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(res, VPX_CODEC_OK);

  vpx_codec_err_t res_dec = decoder_->DecodeFrame(
      (const uint8_t*)svc_get_buffer(&svc_), 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;
  svc_.scale_factors = "4/16,16/16";
  svc_.quantizer_values = "40,30";

  vpx_codec_err_t res =
      vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  ASSERT_EQ(res, VPX_CODEC_OK);

  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(res, VPX_CODEC_OK);
  EXPECT_EQ(1, svc_is_keyframe(&svc_));

  vpx_codec_err_t res_dec = decoder_->DecodeFrame(
      (const uint8_t*)svc_get_buffer(&svc_), 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(res, VPX_CODEC_OK);
  EXPECT_EQ(1, svc_is_keyframe(&svc_));

  res_dec = decoder_->DecodeFrame((const uint8_t*)svc_get_buffer(&svc_),
                                  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(res, VPX_CODEC_OK);
  EXPECT_EQ(0, svc_is_keyframe(&svc_));

  res_dec = decoder_->DecodeFrame((const uint8_t*)svc_get_buffer(&svc_),
                                  svc_get_frame_size(&svc_));
  ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
}

TEST_F(SvcTest, GetLayerResolution) {
  unsigned int layer_width, layer_height;

  svc_.first_frame_full_size = 0;
  svc_.spatial_layers = 2;
  svc_.scale_factors = "4/16,8/16";
  svc_.quantizer_values = "40,30";

  vpx_codec_err_t res =
      vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
  EXPECT_EQ(res, VPX_CODEC_OK);

  // ensure that requested layer is a valid layer
  res = svc_get_layer_resolution(&svc_, svc_.spatial_layers, &layer_width,
                                 &layer_height);
  EXPECT_EQ(res, VPX_CODEC_INVALID_PARAM);

  res = svc_get_layer_resolution(&svc_, 0, &layer_width,
                                 &layer_height);
  EXPECT_EQ(res, VPX_CODEC_OK);
  EXPECT_EQ((unsigned int)(kWidth * 4 / 16), layer_width);
  EXPECT_EQ((unsigned int)(kHeight * 4 / 16), layer_height);

  res = svc_get_layer_resolution(&svc_, 1, &layer_width,
                                 &layer_height);
  EXPECT_EQ(res, VPX_CODEC_OK);
  EXPECT_EQ((unsigned int)(kWidth * 8 / 16), layer_width);
  EXPECT_EQ((unsigned int)(kHeight * 8 / 16), layer_height);
}

}  // namespace