tor-browser

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

forced_max_frame_width_height_test.cc (10087B)


      1 /*
      2 * Copyright (c) 2022, 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 // Tests for https://crbug.com/aomedia/3326.
     13 //
     14 // Set cfg.g_forced_max_frame_width and cfg.g_forced_max_frame_height and
     15 // encode two frames of increasing sizes. The second aom_codec_encode() should
     16 // not crash or have memory errors.
     17 
     18 #include <algorithm>
     19 #include <memory>
     20 #include <vector>
     21 
     22 #include "aom/aomcx.h"
     23 #include "aom/aom_encoder.h"
     24 #include "config/aom_config.h"
     25 #include "gtest/gtest.h"
     26 
     27 namespace {
     28 
     29 // cfg.g_lag_in_frames must be set to 0 or 1 to allow the frame size to change,
     30 // as required by the following check in encoder_set_config() in
     31 // av1/av1_cx_iface.c:
     32 //
     33 //   if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) {
     34 //     if (cfg->g_lag_in_frames > 1 || cfg->g_pass != AOM_RC_ONE_PASS)
     35 //       ERROR("Cannot change width or height after initialization");
     36 //     ...
     37 //   }
     38 
     39 void RunTest(unsigned int usage, unsigned int lag_in_frames,
     40             const char *tune_metric) {
     41  // A buffer of gray samples. Large enough for 128x128 and 256x256, YUV 4:2:0.
     42  constexpr size_t kImageDataSize = 256 * 256 + 2 * 128 * 128;
     43  std::unique_ptr<unsigned char[]> img_data(new unsigned char[kImageDataSize]);
     44  ASSERT_NE(img_data, nullptr);
     45  memset(img_data.get(), 128, kImageDataSize);
     46 
     47  aom_codec_iface_t *iface = aom_codec_av1_cx();
     48  aom_codec_enc_cfg_t cfg;
     49  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, usage));
     50  cfg.g_w = 128;
     51  cfg.g_h = 128;
     52  cfg.g_forced_max_frame_width = 256;
     53  cfg.g_forced_max_frame_height = 256;
     54  cfg.g_lag_in_frames = lag_in_frames;
     55  aom_codec_ctx_t enc;
     56  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
     57  EXPECT_EQ(AOM_CODEC_OK, aom_codec_set_option(&enc, "tune", tune_metric));
     58 
     59  aom_image_t img;
     60  EXPECT_EQ(&img,
     61            aom_img_wrap(&img, AOM_IMG_FMT_I420, 128, 128, 1, img_data.get()));
     62  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
     63 
     64  cfg.g_w = 256;
     65  cfg.g_h = 256;
     66  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg));
     67 
     68  EXPECT_EQ(&img,
     69            aom_img_wrap(&img, AOM_IMG_FMT_I420, 256, 256, 1, img_data.get()));
     70  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
     71 
     72  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 0, 0));
     73  EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
     74 }
     75 
     76 #if !CONFIG_REALTIME_ONLY
     77 
     78 TEST(EncodeForcedMaxFrameWidthHeight, GoodQualityLag0TunePSNR) {
     79  RunTest(AOM_USAGE_GOOD_QUALITY, /*lag_in_frames=*/0, "psnr");
     80 }
     81 
     82 TEST(EncodeForcedMaxFrameWidthHeight, GoodQualityLag0TuneSSIM) {
     83  RunTest(AOM_USAGE_GOOD_QUALITY, /*lag_in_frames=*/0, "ssim");
     84 }
     85 
     86 TEST(EncodeForcedMaxFrameWidthHeight, GoodQualityLag1TunePSNR) {
     87  RunTest(AOM_USAGE_GOOD_QUALITY, /*lag_in_frames=*/1, "psnr");
     88 }
     89 
     90 TEST(EncodeForcedMaxFrameWidthHeight, GoodQualityLag1TuneSSIM) {
     91  RunTest(AOM_USAGE_GOOD_QUALITY, /*lag_in_frames=*/1, "ssim");
     92 }
     93 
     94 void FillImageGradient(aom_image_t *image, int bit_depth) {
     95  assert(image->range == AOM_CR_FULL_RANGE);
     96  for (int plane = 0; plane < 3; plane++) {
     97    const int plane_width = aom_img_plane_width(image, plane);
     98    const int plane_height = aom_img_plane_height(image, plane);
     99    unsigned char *row = image->planes[plane];
    100    const int stride = image->stride[plane];
    101    for (int y = 0; y < plane_height; ++y) {
    102      for (int x = 0; x < plane_width; ++x) {
    103        const int value = (x + y) * ((1 << bit_depth) - 1) /
    104                          std::max(1, plane_width + plane_height - 2);
    105        assert(value >= 0 && value <= (1 << bit_depth) - 1);
    106        if (bit_depth > 8) {
    107          reinterpret_cast<uint16_t *>(row)[x] = static_cast<uint16_t>(value);
    108        } else {
    109          row[x] = static_cast<unsigned char>(value);
    110        }
    111      }
    112      row += stride;
    113    }
    114  }
    115 }
    116 
    117 TEST(EncodeForcedMaxFrameWidthHeight, DimensionDecreasing) {
    118  constexpr int kWidth = 128;
    119  constexpr int kHeight = 128;
    120  constexpr size_t kBufferSize = 3 * kWidth * kHeight;
    121  std::vector<unsigned char> buffer(kBufferSize);
    122 
    123  aom_image_t img;
    124  EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1,
    125                               buffer.data()));
    126  img.cp = AOM_CICP_CP_UNSPECIFIED;
    127  img.tc = AOM_CICP_TC_UNSPECIFIED;
    128  img.mc = AOM_CICP_MC_UNSPECIFIED;
    129  img.range = AOM_CR_FULL_RANGE;
    130  FillImageGradient(&img, 8);
    131 
    132  aom_codec_iface_t *iface = aom_codec_av1_cx();
    133  aom_codec_enc_cfg_t cfg;
    134  EXPECT_EQ(AOM_CODEC_OK,
    135            aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY));
    136  cfg.rc_end_usage = AOM_Q;
    137  cfg.g_profile = 0;
    138  cfg.g_bit_depth = AOM_BITS_8;
    139  cfg.g_input_bit_depth = 8;
    140  cfg.g_w = kWidth;
    141  cfg.g_h = kHeight;
    142  cfg.g_forced_max_frame_width = kWidth;
    143  cfg.g_forced_max_frame_height = kHeight;
    144  cfg.g_lag_in_frames = 1;
    145  cfg.rc_min_quantizer = 20;
    146  cfg.rc_max_quantizer = 40;
    147  aom_codec_ctx_t enc;
    148  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
    149  EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CQ_LEVEL, 30));
    150  EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6));
    151  EXPECT_EQ(AOM_CODEC_OK,
    152            aom_codec_control(&enc, AV1E_SET_COLOR_RANGE, AOM_CR_FULL_RANGE));
    153  EXPECT_EQ(AOM_CODEC_OK,
    154            aom_codec_control(&enc, AOME_SET_TUNING, AOM_TUNE_SSIM));
    155 
    156  // First frame
    157  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
    158  aom_codec_iter_t iter = nullptr;
    159  const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter);
    160  ASSERT_NE(pkt, nullptr);
    161  EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
    162  // pkt->data.frame.flags is 0x1f0011.
    163  EXPECT_NE(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u);
    164  pkt = aom_codec_get_cx_data(&enc, &iter);
    165  EXPECT_EQ(pkt, nullptr);
    166 
    167  // Second frame
    168  constexpr int kWidthSmall = 64;
    169  constexpr int kHeightSmall = 64;
    170  EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidthSmall,
    171                               kHeightSmall, 1, buffer.data()));
    172  img.cp = AOM_CICP_CP_UNSPECIFIED;
    173  img.tc = AOM_CICP_TC_UNSPECIFIED;
    174  img.mc = AOM_CICP_MC_UNSPECIFIED;
    175  img.range = AOM_CR_FULL_RANGE;
    176  FillImageGradient(&img, 8);
    177  cfg.g_w = kWidthSmall;
    178  cfg.g_h = kHeightSmall;
    179  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg));
    180  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
    181  iter = nullptr;
    182  pkt = aom_codec_get_cx_data(&enc, &iter);
    183  ASSERT_NE(pkt, nullptr);
    184  EXPECT_EQ(pkt->kind, AOM_CODEC_CX_FRAME_PKT);
    185  // pkt->data.frame.flags is 0.
    186  EXPECT_EQ(pkt->data.frame.flags & AOM_FRAME_IS_KEY, 0u);
    187  pkt = aom_codec_get_cx_data(&enc, &iter);
    188  EXPECT_EQ(pkt, nullptr);
    189 
    190  // Flush encoder
    191  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 1, 0));
    192  iter = nullptr;
    193  pkt = aom_codec_get_cx_data(&enc, &iter);
    194  EXPECT_EQ(pkt, nullptr);
    195 
    196  EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
    197 }
    198 
    199 #endif  // !CONFIG_REALTIME_ONLY
    200 
    201 TEST(EncodeForcedMaxFrameWidthHeight, RealtimeLag0TunePSNR) {
    202  RunTest(AOM_USAGE_REALTIME, /*lag_in_frames=*/0, "psnr");
    203 }
    204 
    205 TEST(EncodeForcedMaxFrameWidthHeight, RealtimeLag0TuneSSIM) {
    206  RunTest(AOM_USAGE_REALTIME, /*lag_in_frames=*/0, "ssim");
    207 }
    208 
    209 TEST(EncodeForcedMaxFrameWidthHeight, RealtimeLag1TunePSNR) {
    210  RunTest(AOM_USAGE_REALTIME, /*lag_in_frames=*/1, "psnr");
    211 }
    212 
    213 TEST(EncodeForcedMaxFrameWidthHeight, RealtimeLag1TuneSSIM) {
    214  RunTest(AOM_USAGE_REALTIME, /*lag_in_frames=*/1, "ssim");
    215 }
    216 
    217 TEST(EncodeForcedMaxFrameWidthHeight, MaxFrameSizeTooBig) {
    218  aom_codec_iface_t *iface = aom_codec_av1_cx();
    219  aom_codec_enc_cfg_t cfg;
    220  EXPECT_EQ(AOM_CODEC_OK,
    221            aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME));
    222  cfg.g_w = 256;
    223  cfg.g_h = 256;
    224  cfg.g_forced_max_frame_width = 131072;
    225  cfg.g_forced_max_frame_height = 131072;
    226  aom_codec_ctx_t enc;
    227  EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0));
    228 }
    229 
    230 TEST(EncodeForcedMaxFrameWidthHeight, FirstFrameTooBig) {
    231  aom_codec_iface_t *iface = aom_codec_av1_cx();
    232  aom_codec_enc_cfg_t cfg;
    233  EXPECT_EQ(AOM_CODEC_OK,
    234            aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME));
    235  cfg.g_w = 258;
    236  cfg.g_h = 256;
    237  cfg.g_forced_max_frame_width = 256;
    238  cfg.g_forced_max_frame_height = 256;
    239  aom_codec_ctx_t enc;
    240  EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0));
    241  cfg.g_w = 256;
    242  cfg.g_h = 258;
    243  EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_init(&enc, iface, &cfg, 0));
    244  cfg.g_w = 256;
    245  cfg.g_h = 256;
    246  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
    247  EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
    248 }
    249 
    250 TEST(EncodeForcedMaxFrameWidthHeight, SecondFrameTooBig) {
    251  // A buffer of gray samples. Large enough for 128x128 and 256x256, YUV 4:2:0.
    252  constexpr size_t kImageDataSize = 256 * 256 + 2 * 128 * 128;
    253  std::unique_ptr<unsigned char[]> img_data(new unsigned char[kImageDataSize]);
    254  ASSERT_NE(img_data, nullptr);
    255  memset(img_data.get(), 128, kImageDataSize);
    256 
    257  aom_codec_iface_t *iface = aom_codec_av1_cx();
    258  aom_codec_enc_cfg_t cfg;
    259  EXPECT_EQ(AOM_CODEC_OK,
    260            aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME));
    261  cfg.g_w = 128;
    262  cfg.g_h = 128;
    263  cfg.g_forced_max_frame_width = 255;
    264  cfg.g_forced_max_frame_height = 256;
    265  aom_codec_ctx_t enc;
    266  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
    267 
    268  aom_image_t img;
    269  EXPECT_EQ(&img,
    270            aom_img_wrap(&img, AOM_IMG_FMT_I420, 128, 128, 1, img_data.get()));
    271  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0));
    272 
    273  cfg.g_w = 256;
    274  cfg.g_h = 256;
    275  EXPECT_EQ(AOM_CODEC_INVALID_PARAM, aom_codec_enc_config_set(&enc, &cfg));
    276 
    277  EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
    278 }
    279 
    280 }  // namespace