tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

frame_size_tests.cc (13592B)


      1 /*
      2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
      3 *
      4 * This source code is subject to the terms of the BSD 2 Clause License and
      5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
      6 * was not distributed with this source code in the LICENSE file, you can
      7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
      8 * Media Patent License 1.0 was not distributed with this source code in the
      9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
     10 */
     11 
     12 #include <array>
     13 #include <memory>
     14 
     15 #include "gtest/gtest.h"
     16 #include "test/codec_factory.h"
     17 #include "test/video_source.h"
     18 #include "test/util.h"
     19 
     20 namespace {
     21 
     22 class AV1FrameSizeTests : public ::testing::Test,
     23                          public ::libaom_test::EncoderTest {
     24 protected:
     25  AV1FrameSizeTests()
     26      : EncoderTest(&::libaom_test::kAV1), expected_res_(AOM_CODEC_OK) {}
     27  ~AV1FrameSizeTests() override = default;
     28 
     29  void SetUp() override { InitializeConfig(::libaom_test::kRealTime); }
     30 
     31  bool HandleDecodeResult(const aom_codec_err_t res_dec,
     32                          libaom_test::Decoder *decoder) override {
     33    EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError();
     34    return !::testing::Test::HasFailure();
     35  }
     36 
     37  void PreEncodeFrameHook(::libaom_test::VideoSource *video,
     38                          ::libaom_test::Encoder *encoder) override {
     39    if (video->frame() == 0) {
     40      encoder->Control(AOME_SET_CPUUSED, 7);
     41      encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
     42      encoder->Control(AOME_SET_ARNR_MAXFRAMES, 7);
     43      encoder->Control(AOME_SET_ARNR_STRENGTH, 5);
     44    }
     45  }
     46 
     47  int expected_res_;
     48 };
     49 
     50 #if CONFIG_SIZE_LIMIT
     51 // TODO(Casey.Smalley@arm.com) fails due to newer bounds checks that get caught
     52 // before the assert below added in ebc2714d71a834fc32a19eef0a81f51fbc47db01
     53 TEST_F(AV1FrameSizeTests, DISABLED_TestInvalidSizes) {
     54  ::libaom_test::RandomVideoSource video;
     55 
     56  video.SetSize(DECODE_WIDTH_LIMIT + 16, DECODE_HEIGHT_LIMIT + 16);
     57  video.set_limit(2);
     58  expected_res_ = AOM_CODEC_CORRUPT_FRAME;
     59  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
     60 }
     61 
     62 // TODO(Casey.Smalley@arm.com) similar to the above test, needs to be
     63 // updated for the new rejection case
     64 TEST_F(AV1FrameSizeTests, DISABLED_LargeValidSizes) {
     65  ::libaom_test::RandomVideoSource video;
     66 
     67  video.SetSize(DECODE_WIDTH_LIMIT, DECODE_HEIGHT_LIMIT);
     68  video.set_limit(2);
     69  expected_res_ = AOM_CODEC_OK;
     70  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
     71 }
     72 #endif
     73 
     74 TEST_F(AV1FrameSizeTests, OneByOneVideo) {
     75  ::libaom_test::RandomVideoSource video;
     76 
     77  video.SetSize(1, 1);
     78  video.set_limit(2);
     79  expected_res_ = AOM_CODEC_OK;
     80  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
     81 }
     82 
     83 // Parameters: AOM_USAGE_*, aom_rc_mode, cpu-used.
     84 class AV1ResolutionChange
     85    : public testing::TestWithParam<std::tuple<int, aom_rc_mode, int>> {
     86 public:
     87  AV1ResolutionChange()
     88      : usage_(std::get<0>(GetParam())), rc_mode_(std::get<1>(GetParam())),
     89        cpu_used_(std::get<2>(GetParam())) {}
     90  AV1ResolutionChange(const AV1ResolutionChange &) = delete;
     91  AV1ResolutionChange &operator=(const AV1ResolutionChange &) = delete;
     92  ~AV1ResolutionChange() override = default;
     93 
     94 protected:
     95  int usage_;
     96  aom_rc_mode rc_mode_;
     97  int cpu_used_;
     98 };
     99 
    100 TEST_P(AV1ResolutionChange, InvalidRefSize) {
    101  struct FrameSize {
    102    unsigned int width;
    103    unsigned int height;
    104  };
    105  static constexpr std::array<FrameSize, 3> kFrameSizes = { {
    106      { 1768, 200 },
    107      { 50, 200 },
    108      { 850, 200 },
    109  } };
    110 
    111  aom_codec_iface_t *iface = aom_codec_av1_cx();
    112  aom_codec_enc_cfg_t cfg;
    113  ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage_), AOM_CODEC_OK);
    114 
    115  // Resolution changes are only permitted with one pass encoding with no lag.
    116  cfg.g_pass = AOM_RC_ONE_PASS;
    117  cfg.g_lag_in_frames = 0;
    118  cfg.rc_end_usage = rc_mode_;
    119 
    120  aom_codec_ctx_t ctx;
    121  EXPECT_EQ(aom_codec_enc_init(&ctx, iface, &cfg, 0), AOM_CODEC_OK);
    122  std::unique_ptr<aom_codec_ctx_t, decltype(&aom_codec_destroy)> enc(
    123      &ctx, &aom_codec_destroy);
    124  EXPECT_EQ(aom_codec_control(enc.get(), AOME_SET_CPUUSED, cpu_used_),
    125            AOM_CODEC_OK);
    126 
    127  size_t frame_count = 0;
    128  ::libaom_test::RandomVideoSource video;
    129  video.Begin();
    130  constexpr int kNumFramesPerResolution = 2;
    131  for (const auto &frame_size : kFrameSizes) {
    132    cfg.g_w = frame_size.width;
    133    cfg.g_h = frame_size.height;
    134    EXPECT_EQ(aom_codec_enc_config_set(enc.get(), &cfg), AOM_CODEC_OK);
    135    video.SetSize(cfg.g_w, cfg.g_h);
    136 
    137    aom_codec_iter_t iter;
    138    const aom_codec_cx_pkt_t *pkt;
    139 
    140    for (int i = 0; i < kNumFramesPerResolution; ++i) {
    141      video.Next();  // SetSize() does not call FillFrame().
    142      EXPECT_EQ(aom_codec_encode(enc.get(), video.img(), video.pts(),
    143                                 video.duration(), /*flags=*/0),
    144                AOM_CODEC_OK);
    145 
    146      iter = nullptr;
    147      while ((pkt = aom_codec_get_cx_data(enc.get(), &iter)) != nullptr) {
    148        ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
    149        // The frame following a resolution change should be a keyframe as the
    150        // change is too extreme to allow previous references to be used.
    151        if (i == 0 || usage_ == AOM_USAGE_ALL_INTRA) {
    152          EXPECT_NE(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u)
    153              << "frame " << frame_count;
    154        }
    155        frame_count++;
    156      }
    157    }
    158  }
    159 
    160  EXPECT_EQ(frame_count, kNumFramesPerResolution * kFrameSizes.size());
    161 }
    162 
    163 TEST_P(AV1ResolutionChange, RandomInput) {
    164  struct FrameSize {
    165    unsigned int width;
    166    unsigned int height;
    167  };
    168  static constexpr std::array<FrameSize, 4> kFrameSizes = { {
    169      { 50, 200 },
    170      { 100, 200 },
    171      { 100, 300 },
    172      { 200, 400 },
    173  } };
    174 
    175  aom_codec_iface_t *iface = aom_codec_av1_cx();
    176  aom_codec_enc_cfg_t cfg;
    177  ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage_), AOM_CODEC_OK);
    178 
    179  // Resolution changes are only permitted with one pass encoding with no lag.
    180  cfg.g_pass = AOM_RC_ONE_PASS;
    181  cfg.g_lag_in_frames = 0;
    182  cfg.rc_end_usage = rc_mode_;
    183  // For random input source, if max frame sizes are not set, the first encoded
    184  // frame size will be locked as the max frame size, and the encoder will
    185  // identify it as unsupported bitstream.
    186  unsigned int max_width = cfg.g_w;   // default frame width
    187  unsigned int max_height = cfg.g_h;  // default frame height
    188  for (const auto &frame_size : kFrameSizes) {
    189    max_width = frame_size.width > max_width ? frame_size.width : max_width;
    190    max_height =
    191        frame_size.height > max_height ? frame_size.height : max_height;
    192  }
    193  cfg.g_forced_max_frame_width = max_width;
    194  cfg.g_forced_max_frame_height = max_height;
    195 
    196  aom_codec_ctx_t ctx;
    197  EXPECT_EQ(aom_codec_enc_init(&ctx, iface, &cfg, 0), AOM_CODEC_OK);
    198  std::unique_ptr<aom_codec_ctx_t, decltype(&aom_codec_destroy)> enc(
    199      &ctx, &aom_codec_destroy);
    200  EXPECT_EQ(aom_codec_control(enc.get(), AOME_SET_CPUUSED, cpu_used_),
    201            AOM_CODEC_OK);
    202 
    203  size_t frame_count = 0;
    204  ::libaom_test::RandomVideoSource video;
    205  video.Begin();
    206  constexpr int kNumFramesPerResolution = 2;
    207  for (const auto &frame_size : kFrameSizes) {
    208    cfg.g_w = frame_size.width;
    209    cfg.g_h = frame_size.height;
    210    EXPECT_EQ(aom_codec_enc_config_set(enc.get(), &cfg), AOM_CODEC_OK);
    211    video.SetSize(cfg.g_w, cfg.g_h);
    212 
    213    aom_codec_iter_t iter;
    214    const aom_codec_cx_pkt_t *pkt;
    215 
    216    for (int i = 0; i < kNumFramesPerResolution; ++i) {
    217      video.Next();  // SetSize() does not call FillFrame().
    218      EXPECT_EQ(aom_codec_encode(enc.get(), video.img(), video.pts(),
    219                                 video.duration(), /*flags=*/0),
    220                AOM_CODEC_OK);
    221 
    222      iter = nullptr;
    223      while ((pkt = aom_codec_get_cx_data(enc.get(), &iter)) != nullptr) {
    224        ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
    225        // The frame following a resolution change should be a keyframe as the
    226        // change is too extreme to allow previous references to be used.
    227        if (i == 0 || usage_ == AOM_USAGE_ALL_INTRA) {
    228          EXPECT_NE(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u)
    229              << "frame " << frame_count;
    230        }
    231        frame_count++;
    232      }
    233    }
    234  }
    235 
    236  EXPECT_EQ(frame_count, kNumFramesPerResolution * kFrameSizes.size());
    237 }
    238 
    239 TEST_P(AV1ResolutionChange, InvalidInputSize) {
    240  struct FrameSize {
    241    unsigned int width;
    242    unsigned int height;
    243  };
    244  static constexpr std::array<FrameSize, 3> kFrameSizes = { {
    245      { 1768, 0 },
    246      { 0, 200 },
    247      { 850, 200 },
    248  } };
    249 
    250  aom_codec_iface_t *iface = aom_codec_av1_cx();
    251  aom_codec_enc_cfg_t cfg;
    252  ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage_), AOM_CODEC_OK);
    253 
    254  // Resolution changes are only permitted with one pass encoding with no lag.
    255  cfg.g_pass = AOM_RC_ONE_PASS;
    256  cfg.g_lag_in_frames = 0;
    257  cfg.rc_end_usage = rc_mode_;
    258 
    259  aom_codec_ctx_t ctx;
    260  EXPECT_EQ(aom_codec_enc_init(&ctx, iface, &cfg, 0), AOM_CODEC_OK);
    261  std::unique_ptr<aom_codec_ctx_t, decltype(&aom_codec_destroy)> enc(
    262      &ctx, &aom_codec_destroy);
    263  EXPECT_EQ(aom_codec_control(enc.get(), AOME_SET_CPUUSED, cpu_used_),
    264            AOM_CODEC_OK);
    265 
    266  int frame_count = 0;
    267  ::libaom_test::RandomVideoSource video;
    268  video.Begin();
    269  constexpr int kNumFramesPerResolution = 2;
    270  for (const auto &frame_size : kFrameSizes) {
    271    cfg.g_w = frame_size.width;
    272    cfg.g_h = frame_size.height;
    273    if (cfg.g_w < 1 || cfg.g_w > 65536 || cfg.g_h < 1 || cfg.g_h > 65536) {
    274      EXPECT_EQ(aom_codec_enc_config_set(enc.get(), &cfg),
    275                AOM_CODEC_INVALID_PARAM);
    276      continue;
    277    }
    278 
    279    EXPECT_EQ(aom_codec_enc_config_set(enc.get(), &cfg), AOM_CODEC_OK);
    280    video.SetSize(cfg.g_w, cfg.g_h);
    281 
    282    aom_codec_iter_t iter;
    283    const aom_codec_cx_pkt_t *pkt;
    284 
    285    for (int i = 0; i < kNumFramesPerResolution; ++i) {
    286      video.Next();  // SetSize() does not call FillFrame().
    287      EXPECT_EQ(aom_codec_encode(enc.get(), video.img(), video.pts(),
    288                                 video.duration(), /*flags=*/0),
    289                AOM_CODEC_OK);
    290 
    291      iter = nullptr;
    292      while ((pkt = aom_codec_get_cx_data(enc.get(), &iter)) != nullptr) {
    293        ASSERT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
    294        // The frame following a resolution change should be a keyframe as the
    295        // change is too extreme to allow previous references to be used.
    296        if (i == 0 || usage_ == AOM_USAGE_ALL_INTRA) {
    297          EXPECT_NE(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u)
    298              << "frame " << frame_count;
    299        }
    300        frame_count++;
    301      }
    302    }
    303  }
    304 
    305  EXPECT_EQ(frame_count, 2);
    306 }
    307 
    308 INSTANTIATE_TEST_SUITE_P(
    309    Realtime, AV1ResolutionChange,
    310    ::testing::Combine(::testing::Values(AOM_USAGE_REALTIME),
    311                       ::testing::Values(AOM_VBR, AOM_CBR),
    312                       ::testing::Range(6, 11)));
    313 
    314 #if !CONFIG_REALTIME_ONLY
    315 INSTANTIATE_TEST_SUITE_P(
    316    GoodQuality, AV1ResolutionChange,
    317    ::testing::Combine(::testing::Values(AOM_USAGE_GOOD_QUALITY),
    318                       ::testing::Values(AOM_VBR, AOM_CBR, AOM_CQ, AOM_Q),
    319                       ::testing::Range(2, 6)));
    320 INSTANTIATE_TEST_SUITE_P(
    321    GoodQualityLarge, AV1ResolutionChange,
    322    ::testing::Combine(::testing::Values(AOM_USAGE_GOOD_QUALITY),
    323                       ::testing::Values(AOM_VBR, AOM_CBR, AOM_CQ, AOM_Q),
    324                       ::testing::Range(0, 2)));
    325 INSTANTIATE_TEST_SUITE_P(
    326    AllIntra, AV1ResolutionChange,
    327    ::testing::Combine(::testing::Values(AOM_USAGE_ALL_INTRA),
    328                       ::testing::Values(AOM_Q), ::testing::Range(6, 10)));
    329 
    330 struct FrameSizeParam {
    331  unsigned int width;
    332  unsigned int height;
    333 };
    334 
    335 const FrameSizeParam FrameSizeTestParams[] = { { 96, 96 }, { 176, 144 } };
    336 
    337 // This unit test is used to validate the allocated size of compressed data
    338 // (ctx->cx_data) buffer, by feeding pseudo random input to the encoder in
    339 // lossless encoding mode.
    340 //
    341 // If compressed data buffer is not large enough, the av1_get_compressed_data()
    342 // call in av1/av1_cx_iface.c will overflow the buffer.
    343 class AV1LosslessFrameSizeTests
    344    : public ::libaom_test::CodecTestWith2Params<FrameSizeParam,
    345                                                 ::libaom_test::TestMode>,
    346      public ::libaom_test::EncoderTest {
    347 protected:
    348  AV1LosslessFrameSizeTests()
    349      : EncoderTest(GET_PARAM(0)), frame_size_param_(GET_PARAM(1)),
    350        encoding_mode_(GET_PARAM(2)) {}
    351  ~AV1LosslessFrameSizeTests() override = default;
    352 
    353  void SetUp() override { InitializeConfig(encoding_mode_); }
    354 
    355  bool HandleDecodeResult(const aom_codec_err_t res_dec,
    356                          libaom_test::Decoder *decoder) override {
    357    EXPECT_EQ(expected_res_, res_dec) << decoder->DecodeError();
    358    return !::testing::Test::HasFailure();
    359  }
    360 
    361  void PreEncodeFrameHook(::libaom_test::VideoSource *video,
    362                          ::libaom_test::Encoder *encoder) override {
    363    if (video->frame() == 0) {
    364      encoder->Control(AOME_SET_CPUUSED, 6);
    365      encoder->Control(AV1E_SET_LOSSLESS, 1);
    366    }
    367  }
    368 
    369  const FrameSizeParam frame_size_param_;
    370  const ::libaom_test::TestMode encoding_mode_;
    371  int expected_res_;
    372 };
    373 
    374 TEST_P(AV1LosslessFrameSizeTests, LosslessEncode) {
    375  ::libaom_test::RandomVideoSource video;
    376 
    377  video.SetSize(frame_size_param_.width, frame_size_param_.height);
    378  video.set_limit(10);
    379  expected_res_ = AOM_CODEC_OK;
    380  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
    381 }
    382 
    383 AV1_INSTANTIATE_TEST_SUITE(AV1LosslessFrameSizeTests,
    384                           ::testing::ValuesIn(FrameSizeTestParams),
    385                           testing::Values(::libaom_test::kAllIntra));
    386 #endif  // !CONFIG_REALTIME_ONLY
    387 
    388 }  // namespace