tor-browser

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

video_frame_unittest.cc (24339B)


      1 /*
      2 *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "api/video/video_frame.h"
     12 
     13 #include <algorithm>
     14 #include <cstdint>
     15 #include <cstring>
     16 #include <utility>
     17 #include <vector>
     18 
     19 #include "api/scoped_refptr.h"
     20 #include "api/video/i010_buffer.h"
     21 #include "api/video/i210_buffer.h"
     22 #include "api/video/i410_buffer.h"
     23 #include "api/video/i420_buffer.h"
     24 #include "api/video/i422_buffer.h"
     25 #include "api/video/i444_buffer.h"
     26 #include "api/video/nv12_buffer.h"
     27 #include "api/video/video_frame_buffer.h"
     28 #include "api/video/video_rotation.h"
     29 #include "test/fake_texture_frame.h"
     30 #include "test/frame_utils.h"
     31 #include "test/gtest.h"
     32 
     33 namespace webrtc {
     34 
     35 namespace {
     36 
     37 struct SubSampling {
     38  int x;
     39  int y;
     40 };
     41 
     42 SubSampling SubSamplingForType(VideoFrameBuffer::Type type) {
     43  switch (type) {
     44    case VideoFrameBuffer::Type::kI420:
     45      return {.x = 2, .y = 2};
     46    case VideoFrameBuffer::Type::kI420A:
     47      return {.x = 2, .y = 2};
     48    case VideoFrameBuffer::Type::kI422:
     49      return {.x = 2, .y = 1};
     50    case VideoFrameBuffer::Type::kI444:
     51      return {.x = 1, .y = 1};
     52    case VideoFrameBuffer::Type::kI010:
     53      return {.x = 2, .y = 2};
     54    case VideoFrameBuffer::Type::kI210:
     55      return {.x = 2, .y = 1};
     56    case VideoFrameBuffer::Type::kI410:
     57      return {.x = 1, .y = 1};
     58    default:
     59      return {};
     60  }
     61 }
     62 
     63 // Helper function to create a buffer and fill it with a gradient for
     64 // PlanarYuvBuffer based buffers.
     65 template <class T>
     66 scoped_refptr<T> CreateGradient(int width, int height) {
     67  scoped_refptr<T> buffer(T::Create(width, height));
     68  // Initialize with gradient, Y = 128(x/w + y/h), U = 256 x/w, V = 256 y/h
     69  for (int x = 0; x < width; x++) {
     70    for (int y = 0; y < height; y++) {
     71      buffer->MutableDataY()[x + y * width] =
     72          128 * (x * height + y * width) / (width * height);
     73    }
     74  }
     75  int chroma_width = buffer->ChromaWidth();
     76  int chroma_height = buffer->ChromaHeight();
     77  for (int x = 0; x < chroma_width; x++) {
     78    for (int y = 0; y < chroma_height; y++) {
     79      buffer->MutableDataU()[x + y * chroma_width] =
     80          255 * x / (chroma_width - 1);
     81      buffer->MutableDataV()[x + y * chroma_width] =
     82          255 * y / (chroma_height - 1);
     83    }
     84  }
     85  return buffer;
     86 }
     87 
     88 // Helper function to create a buffer and fill it with a gradient.
     89 scoped_refptr<NV12BufferInterface> CreateNV12Gradient(int width, int height) {
     90  scoped_refptr<NV12Buffer> buffer(NV12Buffer::Create(width, height));
     91  // Initialize with gradient, Y = 128(x/w + y/h), U = 256 x/w, V = 256 y/h
     92  for (int x = 0; x < width; x++) {
     93    for (int y = 0; y < height; y++) {
     94      buffer->MutableDataY()[x + y * width] =
     95          128 * (x * height + y * width) / (width * height);
     96    }
     97  }
     98  int chroma_width = buffer->ChromaWidth();
     99  int chroma_height = buffer->ChromaHeight();
    100  for (int x = 0; x < chroma_width; x++) {
    101    for (int y = 0; y < chroma_height; y++) {
    102      buffer->MutableDataUV()[x * 2 + y * buffer->StrideUV()] =
    103          255 * x / (chroma_width - 1);
    104      buffer->MutableDataUV()[x * 2 + 1 + y * buffer->StrideUV()] =
    105          255 * y / (chroma_height - 1);
    106    }
    107  }
    108  return buffer;
    109 }
    110 
    111 // The offsets and sizes describe the rectangle extracted from the
    112 // original (gradient) frame, in relative coordinates where the
    113 // original frame correspond to the unit square, 0.0 <= x, y < 1.0.
    114 template <class T>
    115 void CheckCrop(const T& frame,
    116               double offset_x,
    117               double offset_y,
    118               double rel_width,
    119               double rel_height) {
    120  int width = frame.width();
    121  int height = frame.height();
    122 
    123  SubSampling plane_divider = SubSamplingForType(frame.type());
    124 
    125  // Check that pixel values in the corners match the gradient used
    126  // for initialization.
    127  for (int i = 0; i < 2; i++) {
    128    for (int j = 0; j < 2; j++) {
    129      // Pixel coordinates of the corner.
    130      int x = i * (width - 1);
    131      int y = j * (height - 1);
    132      // Relative coordinates, range 0.0 - 1.0 correspond to the
    133      // size of the uncropped input frame.
    134      double orig_x = offset_x + i * rel_width;
    135      double orig_y = offset_y + j * rel_height;
    136 
    137      EXPECT_NEAR(frame.DataY()[x + y * frame.StrideY()] / 256.0,
    138                  (orig_x + orig_y) / 2, 0.02);
    139      EXPECT_NEAR(frame.DataU()[x / plane_divider.x +
    140                                (y / plane_divider.y) * frame.StrideU()] /
    141                      256.0,
    142                  orig_x, 0.02);
    143      EXPECT_NEAR(frame.DataV()[x / plane_divider.x +
    144                                (y / plane_divider.y) * frame.StrideV()] /
    145                      256.0,
    146                  orig_y, 0.02);
    147    }
    148  }
    149 }
    150 
    151 template <class T>
    152 void CheckRotate(int width,
    153                 int height,
    154                 VideoRotation rotation,
    155                 const T& rotated) {
    156  int rotated_width = width;
    157  int rotated_height = height;
    158 
    159  if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) {
    160    std::swap(rotated_width, rotated_height);
    161  }
    162  EXPECT_EQ(rotated_width, rotated.width());
    163  EXPECT_EQ(rotated_height, rotated.height());
    164 
    165  // Clock-wise order (with 0,0 at top-left)
    166  const struct {
    167    int x;
    168    int y;
    169  } corners[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
    170  // Corresponding corner colors of the frame produced by CreateGradient.
    171  const struct {
    172    int y;
    173    int u;
    174    int v;
    175  } colors[] = {{0, 0, 0}, {127, 255, 0}, {255, 255, 255}, {127, 0, 255}};
    176  int corner_offset = static_cast<int>(rotation) / 90;
    177 
    178  SubSampling plane_divider = SubSamplingForType(rotated.type());
    179 
    180  for (int i = 0; i < 4; i++) {
    181    int j = (i + corner_offset) % 4;
    182    int x = corners[j].x * (rotated_width - 1);
    183    int y = corners[j].y * (rotated_height - 1);
    184    EXPECT_EQ(colors[i].y, rotated.DataY()[x + y * rotated.StrideY()]);
    185    if (rotated.type() == VideoFrameBuffer::Type::kI422 ||
    186        rotated.type() == VideoFrameBuffer::Type::kI210) {
    187      EXPECT_NEAR(colors[i].u,
    188                  rotated.DataU()[(x / plane_divider.x) +
    189                                  (y / plane_divider.y) * rotated.StrideU()],
    190                  1);
    191      EXPECT_NEAR(colors[i].v,
    192                  rotated.DataV()[(x / plane_divider.x) +
    193                                  (y / plane_divider.y) * rotated.StrideV()],
    194                  1);
    195    } else {
    196      EXPECT_EQ(colors[i].u,
    197                rotated.DataU()[(x / plane_divider.x) +
    198                                (y / plane_divider.y) * rotated.StrideU()]);
    199      EXPECT_EQ(colors[i].v,
    200                rotated.DataV()[(x / plane_divider.x) +
    201                                (y / plane_divider.y) * rotated.StrideV()]);
    202    }
    203  }
    204 }
    205 
    206 }  // namespace
    207 
    208 TEST(TestVideoFrame, WidthHeightValues) {
    209  VideoFrame frame =
    210      VideoFrame::Builder()
    211          .set_video_frame_buffer(I420Buffer::Create(10, 10, 10, 14, 90))
    212          .set_rotation(kVideoRotation_0)
    213          .set_timestamp_ms(789)
    214          .build();
    215  const int valid_value = 10;
    216  EXPECT_EQ(valid_value, frame.width());
    217  EXPECT_EQ(valid_value, frame.height());
    218  frame.set_rtp_timestamp(123u);
    219  EXPECT_EQ(123u, frame.rtp_timestamp());
    220  frame.set_ntp_time_ms(456);
    221  EXPECT_EQ(456, frame.ntp_time_ms());
    222  EXPECT_EQ(789, frame.render_time_ms());
    223 }
    224 
    225 TEST(TestVideoFrame, ShallowCopy) {
    226  uint32_t timestamp = 1;
    227  int64_t ntp_time_ms = 2;
    228  int64_t timestamp_us = 3;
    229  int stride_y = 15;
    230  int stride_u = 10;
    231  int stride_v = 10;
    232  int width = 15;
    233  int height = 15;
    234 
    235  const int kSizeY = 400;
    236  const int kSizeU = 100;
    237  const int kSizeV = 100;
    238  const VideoRotation kRotation = kVideoRotation_270;
    239  uint8_t buffer_y[kSizeY];
    240  uint8_t buffer_u[kSizeU];
    241  uint8_t buffer_v[kSizeV];
    242  memset(buffer_y, 16, kSizeY);
    243  memset(buffer_u, 8, kSizeU);
    244  memset(buffer_v, 4, kSizeV);
    245 
    246  VideoFrame frame1 = VideoFrame::Builder()
    247                          .set_video_frame_buffer(I420Buffer::Copy(
    248                              width, height, buffer_y, stride_y, buffer_u,
    249                              stride_u, buffer_v, stride_v))
    250                          .set_rotation(kRotation)
    251                          .set_timestamp_us(0)
    252                          .build();
    253  frame1.set_rtp_timestamp(timestamp);
    254  frame1.set_ntp_time_ms(ntp_time_ms);
    255  frame1.set_timestamp_us(timestamp_us);
    256  VideoFrame frame2(frame1);
    257 
    258  EXPECT_EQ(frame1.video_frame_buffer(), frame2.video_frame_buffer());
    259  const I420BufferInterface* yuv1 = frame1.video_frame_buffer()->GetI420();
    260  const I420BufferInterface* yuv2 = frame2.video_frame_buffer()->GetI420();
    261  EXPECT_EQ(yuv1->DataY(), yuv2->DataY());
    262  EXPECT_EQ(yuv1->DataU(), yuv2->DataU());
    263  EXPECT_EQ(yuv1->DataV(), yuv2->DataV());
    264 
    265  EXPECT_EQ(frame2.rtp_timestamp(), frame1.rtp_timestamp());
    266  EXPECT_EQ(frame2.ntp_time_ms(), frame1.ntp_time_ms());
    267  EXPECT_EQ(frame2.timestamp_us(), frame1.timestamp_us());
    268  EXPECT_EQ(frame2.rotation(), frame1.rotation());
    269 
    270  frame2.set_rtp_timestamp(timestamp + 1);
    271  frame2.set_ntp_time_ms(ntp_time_ms + 1);
    272  frame2.set_timestamp_us(timestamp_us + 1);
    273  frame2.set_rotation(kVideoRotation_90);
    274 
    275  EXPECT_NE(frame2.rtp_timestamp(), frame1.rtp_timestamp());
    276  EXPECT_NE(frame2.ntp_time_ms(), frame1.ntp_time_ms());
    277  EXPECT_NE(frame2.timestamp_us(), frame1.timestamp_us());
    278  EXPECT_NE(frame2.rotation(), frame1.rotation());
    279 }
    280 
    281 TEST(TestVideoFrame, TextureInitialValues) {
    282  VideoFrame frame =
    283      test::FakeNativeBuffer::CreateFrame(640, 480, 100, 10, kVideoRotation_0);
    284  EXPECT_EQ(640, frame.width());
    285  EXPECT_EQ(480, frame.height());
    286  EXPECT_EQ(100u, frame.rtp_timestamp());
    287  EXPECT_EQ(10, frame.render_time_ms());
    288  ASSERT_TRUE(frame.video_frame_buffer() != nullptr);
    289  EXPECT_TRUE(frame.video_frame_buffer()->type() ==
    290              VideoFrameBuffer::Type::kNative);
    291 
    292  frame.set_rtp_timestamp(200);
    293  EXPECT_EQ(200u, frame.rtp_timestamp());
    294  frame.set_timestamp_us(20);
    295  EXPECT_EQ(20, frame.timestamp_us());
    296 }
    297 
    298 template <typename T>
    299 class TestPlanarYuvBuffer : public ::testing::Test {};
    300 TYPED_TEST_SUITE_P(TestPlanarYuvBuffer);
    301 
    302 template <class T>
    303 scoped_refptr<T> CreateAndFillBuffer() {
    304  auto buf = T::Create(20, 10);
    305  memset(buf->MutableDataY(), 1, 200);
    306 
    307  if (buf->type() == VideoFrameBuffer::Type::kI444 ||
    308      buf->type() == VideoFrameBuffer::Type::kI410) {
    309    memset(buf->MutableDataU(), 2, 200);
    310    memset(buf->MutableDataV(), 3, 200);
    311  } else if (buf->type() == VideoFrameBuffer::Type::kI422 ||
    312             buf->type() == VideoFrameBuffer::Type::kI210) {
    313    memset(buf->MutableDataU(), 2, 100);
    314    memset(buf->MutableDataV(), 3, 100);
    315  } else {
    316    memset(buf->MutableDataU(), 2, 50);
    317    memset(buf->MutableDataV(), 3, 50);
    318  }
    319 
    320  return buf;
    321 }
    322 
    323 TYPED_TEST_P(TestPlanarYuvBuffer, Copy) {
    324  scoped_refptr<TypeParam> buf1 = CreateAndFillBuffer<TypeParam>();
    325  scoped_refptr<TypeParam> buf2 = TypeParam::Copy(*buf1);
    326  EXPECT_TRUE(test::FrameBufsEqual(buf1, buf2));
    327 }
    328 
    329 TYPED_TEST_P(TestPlanarYuvBuffer, CropXCenter) {
    330  scoped_refptr<TypeParam> buf = CreateGradient<TypeParam>(200, 100);
    331 
    332  // Pure center cropping, no scaling.
    333  scoped_refptr<TypeParam> scaled_buffer = TypeParam::Create(100, 100);
    334  scaled_buffer->CropAndScaleFrom(*buf, 50, 0, 100, 100);
    335  CheckCrop<TypeParam>(*scaled_buffer, 0.25, 0.0, 0.5, 1.0);
    336 }
    337 
    338 TYPED_TEST_P(TestPlanarYuvBuffer, CropXNotCenter) {
    339  scoped_refptr<TypeParam> buf = CreateGradient<TypeParam>(200, 100);
    340 
    341  // Non-center cropping, no scaling.
    342  scoped_refptr<TypeParam> scaled_buffer = TypeParam::Create(100, 100);
    343  scaled_buffer->CropAndScaleFrom(*buf, 25, 0, 100, 100);
    344  CheckCrop<TypeParam>(*scaled_buffer, 0.125, 0.0, 0.5, 1.0);
    345 }
    346 
    347 TYPED_TEST_P(TestPlanarYuvBuffer, CropYCenter) {
    348  scoped_refptr<TypeParam> buf = CreateGradient<TypeParam>(100, 200);
    349 
    350  // Pure center cropping, no scaling.
    351  scoped_refptr<TypeParam> scaled_buffer = TypeParam::Create(100, 100);
    352  scaled_buffer->CropAndScaleFrom(*buf, 0, 50, 100, 100);
    353  CheckCrop<TypeParam>(*scaled_buffer, 0.0, 0.25, 1.0, 0.5);
    354 }
    355 
    356 TYPED_TEST_P(TestPlanarYuvBuffer, CropYNotCenter) {
    357  scoped_refptr<TypeParam> buf = CreateGradient<TypeParam>(100, 200);
    358 
    359  // Pure center cropping, no scaling.
    360  scoped_refptr<TypeParam> scaled_buffer = TypeParam::Create(100, 100);
    361  scaled_buffer->CropAndScaleFrom(*buf, 0, 25, 100, 100);
    362  CheckCrop<TypeParam>(*scaled_buffer, 0.0, 0.125, 1.0, 0.5);
    363 }
    364 
    365 TYPED_TEST_P(TestPlanarYuvBuffer, CropAndScale16x9) {
    366  const int buffer_width = 640;
    367  const int buffer_height = 480;
    368  const int crop_width = 320;
    369  const int crop_height = 180;
    370  scoped_refptr<TypeParam> buf = CreateGradient<TypeParam>(640, 480);
    371 
    372  // Pure center cropping, no scaling.
    373  const int out_width =
    374      std::min(buffer_width, crop_width * buffer_height / crop_height);
    375  const int out_height =
    376      std::min(buffer_height, crop_height * buffer_width / crop_width);
    377  scoped_refptr<TypeParam> scaled_buffer =
    378      TypeParam::Create(out_width, out_height);
    379  scaled_buffer->CropAndScaleFrom(*buf, (buffer_width - out_width) / 2,
    380                                  (buffer_height - out_height) / 2, out_width,
    381                                  out_height);
    382  CheckCrop<TypeParam>(*scaled_buffer, 0.0, 0.125, 1.0, 0.75);
    383 }
    384 
    385 REGISTER_TYPED_TEST_SUITE_P(TestPlanarYuvBuffer,
    386                            Copy,
    387                            CropXCenter,
    388                            CropXNotCenter,
    389                            CropYCenter,
    390                            CropYNotCenter,
    391                            CropAndScale16x9);
    392 
    393 using TestTypesAll = ::testing::Types<I420Buffer,
    394                                      I010Buffer,
    395                                      I444Buffer,
    396                                      I422Buffer,
    397                                      I210Buffer,
    398                                      I410Buffer>;
    399 INSTANTIATE_TYPED_TEST_SUITE_P(All, TestPlanarYuvBuffer, TestTypesAll);
    400 
    401 template <class T>
    402 class TestPlanarYuvBufferScale : public ::testing::Test {};
    403 TYPED_TEST_SUITE_P(TestPlanarYuvBufferScale);
    404 
    405 TYPED_TEST_P(TestPlanarYuvBufferScale, Scale) {
    406  scoped_refptr<TypeParam> buf = CreateGradient<TypeParam>(200, 100);
    407 
    408  // Pure scaling, no cropping.
    409  scoped_refptr<TypeParam> scaled_buffer = TypeParam::Create(150, 75);
    410  scaled_buffer->ScaleFrom(*buf);
    411  CheckCrop<TypeParam>(*scaled_buffer, 0.0, 0.0, 1.0, 1.0);
    412 }
    413 
    414 REGISTER_TYPED_TEST_SUITE_P(TestPlanarYuvBufferScale, Scale);
    415 
    416 using TestTypesScale =
    417    ::testing::Types<I420Buffer, I010Buffer, I210Buffer, I410Buffer>;
    418 INSTANTIATE_TYPED_TEST_SUITE_P(All, TestPlanarYuvBufferScale, TestTypesScale);
    419 
    420 template <class T>
    421 class TestPlanarYuvBufferRotate : public ::testing::Test {
    422 public:
    423  std::vector<webrtc::VideoRotation> RotationParams = {
    424      kVideoRotation_0, kVideoRotation_90, kVideoRotation_180,
    425      kVideoRotation_270};
    426 };
    427 
    428 TYPED_TEST_SUITE_P(TestPlanarYuvBufferRotate);
    429 
    430 TYPED_TEST_P(TestPlanarYuvBufferRotate, Rotates) {
    431  for (const VideoRotation& rotation : this->RotationParams) {
    432    scoped_refptr<TypeParam> buffer = CreateGradient<TypeParam>(640, 480);
    433    scoped_refptr<TypeParam> rotated_buffer =
    434        TypeParam::Rotate(*buffer, rotation);
    435    CheckRotate(640, 480, rotation, *rotated_buffer);
    436  }
    437 }
    438 
    439 REGISTER_TYPED_TEST_SUITE_P(TestPlanarYuvBufferRotate, Rotates);
    440 
    441 using TestTypesRotate = ::testing::
    442    Types<I420Buffer, I010Buffer, I444Buffer, I422Buffer, I210Buffer>;
    443 INSTANTIATE_TYPED_TEST_SUITE_P(Rotate,
    444                               TestPlanarYuvBufferRotate,
    445                               TestTypesRotate);
    446 
    447 TEST(TestNV12Buffer, CropAndScale) {
    448  const int kSourceWidth = 640;
    449  const int kSourceHeight = 480;
    450  const int kScaledWidth = 320;
    451  const int kScaledHeight = 240;
    452  const int kCropLeft = 40;
    453  const int kCropTop = 30;
    454  const int kCropRight = 0;
    455  const int kCropBottom = 30;
    456 
    457  scoped_refptr<VideoFrameBuffer> buf =
    458      CreateNV12Gradient(kSourceWidth, kSourceHeight);
    459 
    460  scoped_refptr<VideoFrameBuffer> scaled_buffer = buf->CropAndScale(
    461      kCropLeft, kCropTop, kSourceWidth - kCropLeft - kCropRight,
    462      kSourceHeight - kCropTop - kCropBottom, kScaledWidth, kScaledHeight);
    463 
    464  // Parameters to CheckCrop indicate what part of the source frame is in the
    465  // scaled frame.
    466  const float kOffsetX = (kCropLeft + 0.0) / kSourceWidth;
    467  const float kOffsetY = (kCropTop + 0.0) / kSourceHeight;
    468  const float kRelativeWidth =
    469      (kSourceWidth - kCropLeft - kCropRight + 0.0) / kSourceWidth;
    470  const float kRelativeHeight =
    471      (kSourceHeight - kCropTop - kCropBottom + 0.0) / kSourceHeight;
    472  CheckCrop(*scaled_buffer->ToI420(), kOffsetX, kOffsetY, kRelativeWidth,
    473            kRelativeHeight);
    474 }
    475 
    476 TEST(TestUpdateRect, CanCompare) {
    477  VideoFrame::UpdateRect a = {
    478      .offset_x = 0, .offset_y = 0, .width = 100, .height = 200};
    479  VideoFrame::UpdateRect b = {
    480      .offset_x = 0, .offset_y = 0, .width = 100, .height = 200};
    481  VideoFrame::UpdateRect c = {
    482      .offset_x = 1, .offset_y = 0, .width = 100, .height = 200};
    483  VideoFrame::UpdateRect d = {
    484      .offset_x = 0, .offset_y = 1, .width = 100, .height = 200};
    485  EXPECT_TRUE(a == b);
    486  EXPECT_FALSE(a == c);
    487  EXPECT_FALSE(a == d);
    488 }
    489 
    490 TEST(TestUpdateRect, ComputesIsEmpty) {
    491  VideoFrame::UpdateRect a = {
    492      .offset_x = 0, .offset_y = 0, .width = 0, .height = 0};
    493  VideoFrame::UpdateRect b = {
    494      .offset_x = 0, .offset_y = 0, .width = 100, .height = 200};
    495  VideoFrame::UpdateRect c = {
    496      .offset_x = 1, .offset_y = 100, .width = 0, .height = 0};
    497  VideoFrame::UpdateRect d = {
    498      .offset_x = 1, .offset_y = 100, .width = 100, .height = 200};
    499  EXPECT_TRUE(a.IsEmpty());
    500  EXPECT_FALSE(b.IsEmpty());
    501  EXPECT_TRUE(c.IsEmpty());
    502  EXPECT_FALSE(d.IsEmpty());
    503 }
    504 
    505 TEST(TestUpdateRectUnion, NonIntersecting) {
    506  VideoFrame::UpdateRect a = {
    507      .offset_x = 0, .offset_y = 0, .width = 10, .height = 20};
    508  VideoFrame::UpdateRect b = {
    509      .offset_x = 100, .offset_y = 200, .width = 10, .height = 20};
    510  a.Union(b);
    511  EXPECT_EQ(a, VideoFrame::UpdateRect({0, 0, 110, 220}));
    512 }
    513 
    514 TEST(TestUpdateRectUnion, Intersecting) {
    515  VideoFrame::UpdateRect a = {
    516      .offset_x = 0, .offset_y = 0, .width = 10, .height = 10};
    517  VideoFrame::UpdateRect b = {
    518      .offset_x = 5, .offset_y = 5, .width = 30, .height = 20};
    519  a.Union(b);
    520  EXPECT_EQ(a, VideoFrame::UpdateRect({0, 0, 35, 25}));
    521 }
    522 
    523 TEST(TestUpdateRectUnion, OneInsideAnother) {
    524  VideoFrame::UpdateRect a = {
    525      .offset_x = 0, .offset_y = 0, .width = 100, .height = 100};
    526  VideoFrame::UpdateRect b = {
    527      .offset_x = 5, .offset_y = 5, .width = 30, .height = 20};
    528  a.Union(b);
    529  EXPECT_EQ(a, VideoFrame::UpdateRect({0, 0, 100, 100}));
    530 }
    531 
    532 TEST(TestUpdateRectIntersect, NonIntersecting) {
    533  VideoFrame::UpdateRect a = {
    534      .offset_x = 0, .offset_y = 0, .width = 10, .height = 20};
    535  VideoFrame::UpdateRect b = {
    536      .offset_x = 100, .offset_y = 200, .width = 10, .height = 20};
    537  a.Intersect(b);
    538  EXPECT_EQ(a, VideoFrame::UpdateRect({0, 0, 0, 0}));
    539 }
    540 
    541 TEST(TestUpdateRectIntersect, Intersecting) {
    542  VideoFrame::UpdateRect a = {
    543      .offset_x = 0, .offset_y = 0, .width = 10, .height = 10};
    544  VideoFrame::UpdateRect b = {
    545      .offset_x = 5, .offset_y = 5, .width = 30, .height = 20};
    546  a.Intersect(b);
    547  EXPECT_EQ(a, VideoFrame::UpdateRect({5, 5, 5, 5}));
    548 }
    549 
    550 TEST(TestUpdateRectIntersect, OneInsideAnother) {
    551  VideoFrame::UpdateRect a = {
    552      .offset_x = 0, .offset_y = 0, .width = 100, .height = 100};
    553  VideoFrame::UpdateRect b = {
    554      .offset_x = 5, .offset_y = 5, .width = 30, .height = 20};
    555  a.Intersect(b);
    556  EXPECT_EQ(a, VideoFrame::UpdateRect({5, 5, 30, 20}));
    557 }
    558 
    559 TEST(TestUpdateRectScale, NoScale) {
    560  const int width = 640;
    561  const int height = 480;
    562  VideoFrame::UpdateRect a = {
    563      .offset_x = 100, .offset_y = 50, .width = 100, .height = 200};
    564  VideoFrame::UpdateRect scaled =
    565      a.ScaleWithFrame(width, height, 0, 0, width, height, width, height);
    566  EXPECT_EQ(scaled, VideoFrame::UpdateRect({100, 50, 100, 200}));
    567 }
    568 
    569 TEST(TestUpdateRectScale, CropOnly) {
    570  const int width = 640;
    571  const int height = 480;
    572  VideoFrame::UpdateRect a = {
    573      .offset_x = 100, .offset_y = 50, .width = 100, .height = 200};
    574  VideoFrame::UpdateRect scaled = a.ScaleWithFrame(
    575      width, height, 10, 10, width - 20, height - 20, width - 20, height - 20);
    576  EXPECT_EQ(scaled, VideoFrame::UpdateRect({90, 40, 100, 200}));
    577 }
    578 
    579 TEST(TestUpdateRectScale, CropOnlyToOddOffset) {
    580  const int width = 640;
    581  const int height = 480;
    582  VideoFrame::UpdateRect a = {
    583      .offset_x = 100, .offset_y = 50, .width = 100, .height = 200};
    584  VideoFrame::UpdateRect scaled = a.ScaleWithFrame(
    585      width, height, 5, 5, width - 10, height - 10, width - 10, height - 10);
    586  EXPECT_EQ(scaled, VideoFrame::UpdateRect({94, 44, 102, 202}));
    587 }
    588 
    589 TEST(TestUpdateRectScale, ScaleByHalf) {
    590  const int width = 640;
    591  const int height = 480;
    592  VideoFrame::UpdateRect a = {
    593      .offset_x = 100, .offset_y = 60, .width = 100, .height = 200};
    594  VideoFrame::UpdateRect scaled = a.ScaleWithFrame(
    595      width, height, 0, 0, width, height, width / 2, height / 2);
    596  // Scaled by half and +2 pixels in all directions.
    597  EXPECT_EQ(scaled, VideoFrame::UpdateRect({48, 28, 54, 104}));
    598 }
    599 
    600 TEST(TestUpdateRectScale, CropToUnchangedRegionBelowUpdateRect) {
    601  const int width = 640;
    602  const int height = 480;
    603  VideoFrame::UpdateRect a = {
    604      .offset_x = 100, .offset_y = 60, .width = 100, .height = 200};
    605  VideoFrame::UpdateRect scaled = a.ScaleWithFrame(
    606      width, height, (width - 10) / 2, (height - 10) / 2, 10, 10, 10, 10);
    607  // Update is out of the cropped frame.
    608  EXPECT_EQ(scaled, VideoFrame::UpdateRect({0, 0, 0, 0}));
    609 }
    610 
    611 TEST(TestUpdateRectScale, CropToUnchangedRegionAboveUpdateRect) {
    612  const int width = 640;
    613  const int height = 480;
    614  VideoFrame::UpdateRect a = {
    615      .offset_x = 600, .offset_y = 400, .width = 10, .height = 10};
    616  VideoFrame::UpdateRect scaled = a.ScaleWithFrame(
    617      width, height, (width - 10) / 2, (height - 10) / 2, 10, 10, 10, 10);
    618  // Update is out of the cropped frame.
    619  EXPECT_EQ(scaled, VideoFrame::UpdateRect({0, 0, 0, 0}));
    620 }
    621 
    622 TEST(TestUpdateRectScale, CropInsideUpdate) {
    623  const int width = 640;
    624  const int height = 480;
    625  VideoFrame::UpdateRect a = {
    626      .offset_x = 300, .offset_y = 200, .width = 100, .height = 100};
    627  VideoFrame::UpdateRect scaled = a.ScaleWithFrame(
    628      width, height, (width - 10) / 2, (height - 10) / 2, 10, 10, 10, 10);
    629  // Cropped frame is inside the update rect.
    630  EXPECT_EQ(scaled, VideoFrame::UpdateRect({0, 0, 10, 10}));
    631 }
    632 
    633 TEST(TestUpdateRectScale, CropAndScaleByHalf) {
    634  const int width = 640;
    635  const int height = 480;
    636  VideoFrame::UpdateRect a = {
    637      .offset_x = 100, .offset_y = 60, .width = 100, .height = 200};
    638  VideoFrame::UpdateRect scaled =
    639      a.ScaleWithFrame(width, height, 10, 10, width - 20, height - 20,
    640                       (width - 20) / 2, (height - 20) / 2);
    641  // Scaled by half and +3 pixels in all directions, because of odd offset after
    642  // crop and scale.
    643  EXPECT_EQ(scaled, VideoFrame::UpdateRect({42, 22, 56, 106}));
    644 }
    645 
    646 TEST(TestVideoFrame, IsRepeatFrame) {
    647  // Defaults to false.
    648  VideoFrame frame1 = VideoFrame::Builder()
    649                          .set_video_frame_buffer(I420Buffer::Create(10, 10))
    650                          .set_rotation(kVideoRotation_0)
    651                          .set_timestamp_ms(123)
    652                          .build();
    653  EXPECT_FALSE(frame1.is_repeat_frame());
    654 
    655  // Set to true.
    656  VideoFrame frame2 = VideoFrame::Builder()
    657                          .set_video_frame_buffer(I420Buffer::Create(10, 10))
    658                          .set_rotation(kVideoRotation_0)
    659                          .set_timestamp_ms(456)
    660                          .set_is_repeat_frame(true)
    661                          .build();
    662  EXPECT_TRUE(frame2.is_repeat_frame());
    663 
    664  // Set to false.
    665  VideoFrame frame3 = VideoFrame::Builder()
    666                          .set_video_frame_buffer(I420Buffer::Create(10, 10))
    667                          .set_rotation(kVideoRotation_0)
    668                          .set_timestamp_ms(789)
    669                          .set_is_repeat_frame(false)
    670                          .build();
    671  EXPECT_FALSE(frame3.is_repeat_frame());
    672 }
    673 
    674 }  // namespace webrtc