summaryrefslogtreecommitdiff
path: root/chromium/media/capture/video/mac/pixel_buffer_transferer_mac_unittest.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/capture/video/mac/pixel_buffer_transferer_mac_unittest.mm')
-rw-r--r--chromium/media/capture/video/mac/pixel_buffer_transferer_mac_unittest.mm268
1 files changed, 268 insertions, 0 deletions
diff --git a/chromium/media/capture/video/mac/pixel_buffer_transferer_mac_unittest.mm b/chromium/media/capture/video/mac/pixel_buffer_transferer_mac_unittest.mm
new file mode 100644
index 00000000000..fa00dfca33d
--- /dev/null
+++ b/chromium/media/capture/video/mac/pixel_buffer_transferer_mac_unittest.mm
@@ -0,0 +1,268 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/video/mac/pixel_buffer_transferer_mac.h"
+
+#include <cmath>
+#include <vector>
+
+#include "base/logging.h"
+#include "media/capture/video/mac/pixel_buffer_pool_mac.h"
+#include "media/capture/video/mac/test/pixel_buffer_test_utils_mac.h"
+#include "media/capture/video/mac/video_capture_device_avfoundation_utils_mac.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+namespace {
+
+constexpr uint8_t kColorR = 255u;
+constexpr uint8_t kColorG = 127u;
+constexpr uint8_t kColorB = 63u;
+
+// Common pixel formats that we want to test. This is partially based on
+// VideoCaptureDeviceAVFoundation::FourCCToChromiumPixelFormat but we do not
+// include MJPEG because compressed formats are not supported by the
+// PixelBufferPool. In addition to the formats supported for capturing, we also
+// test I420, which all captured formats are normally converted to in software
+// making it a sensible destination format.
+
+// media::PIXEL_FORMAT_NV12 a.k.a. "420v"
+constexpr OSType kPixelFormatNv12 =
+ kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+// media::PIXEL_FORMAT_UYVY a.k.a. "2vuy"
+constexpr OSType kPixelFormatUyvy = kCVPixelFormatType_422YpCbCr8;
+// media::PIXEL_FORMAT_YUY2 a.k.a. "yuvs"
+constexpr OSType kPixelFormatYuvs = kCVPixelFormatType_422YpCbCr8_yuvs;
+// media::PIXEL_FORMAT_I420 a.k.a. "y420"
+constexpr OSType kPixelFormatI420 = kCVPixelFormatType_420YpCbCr8Planar;
+
+} // namespace
+
+TEST(PixelBufferTransfererTest, CanCopyYuvsAndVerifyColor) {
+ constexpr OSType kPixelFormat = kPixelFormatYuvs;
+ constexpr int kWidth = 32;
+ constexpr int kHeight = 32;
+ PixelBufferTransferer transferer;
+ // Source: A single colored buffer.
+ std::unique_ptr<ByteArrayPixelBuffer> source =
+ CreateYuvsPixelBufferFromSingleRgbColor(kWidth, kHeight, kColorR, kColorG,
+ kColorB);
+ // Destination buffer: A same-sized YUVS buffer.
+ base::ScopedCFTypeRef<CVPixelBufferRef> destination =
+ PixelBufferPool::Create(kPixelFormat, kWidth, kHeight, 1)->CreateBuffer();
+ EXPECT_TRUE(transferer.TransferImage(source->pixel_buffer, destination));
+ // Verify the result is the same color.
+ EXPECT_TRUE(YuvsIOSurfaceIsSingleColor(CVPixelBufferGetIOSurface(destination),
+ kColorR, kColorG, kColorB));
+}
+
+TEST(PixelBufferTransfererTest, CanScaleYuvsAndVerifyColor) {
+ constexpr OSType kPixelFormat = kPixelFormatYuvs;
+ constexpr int kSourceWidth = 32;
+ constexpr int kSourceHeight = 32;
+ constexpr int kDestinationWidth = 16;
+ constexpr int kDestinationHeight = 16;
+ PixelBufferTransferer transferer;
+ // Source: A single colored buffer.
+ std::unique_ptr<ByteArrayPixelBuffer> source =
+ CreateYuvsPixelBufferFromSingleRgbColor(kSourceWidth, kSourceHeight,
+ kColorR, kColorG, kColorB);
+ // Destination buffer: A downscaled YUVS buffer.
+ base::ScopedCFTypeRef<CVPixelBufferRef> destination =
+ PixelBufferPool::Create(kPixelFormat, kDestinationWidth,
+ kDestinationHeight, 1)
+ ->CreateBuffer();
+ EXPECT_TRUE(transferer.TransferImage(source->pixel_buffer, destination));
+ // Verify the result is the same color.
+ EXPECT_TRUE(YuvsIOSurfaceIsSingleColor(CVPixelBufferGetIOSurface(destination),
+ kColorR, kColorG, kColorB));
+}
+
+TEST(PixelBufferTransfererTest, CanScaleYuvsAndVerifyCheckerPattern) {
+ // Note: The ARGB -> YUVS -> ARGB conversions results in a small loss of
+ // information, so for the checker pattern to be intact the buffer can't be
+ // tiny (e.g. 4x4).
+ constexpr int kSourceWidth = 64;
+ constexpr int kSourceHeight = 64;
+ constexpr int kSourceNumTilesAcross = 4;
+ constexpr int kDestinationWidth = 32;
+ constexpr int kDestinationHeight = 32;
+ PixelBufferTransferer transferer;
+ // Source: A single colored buffer.
+ std::unique_ptr<ByteArrayPixelBuffer> source =
+ CreateYuvsPixelBufferFromArgbBuffer(
+ kSourceWidth, kSourceHeight,
+ CreateArgbCheckerPatternBuffer(kSourceWidth, kSourceHeight,
+ kSourceNumTilesAcross));
+ // Destination buffer: A downscaled YUVS buffer.
+ base::ScopedCFTypeRef<CVPixelBufferRef> destination =
+ PixelBufferPool::Create(kPixelFormatYuvs, kDestinationWidth,
+ kDestinationHeight, 1)
+ ->CreateBuffer();
+ EXPECT_TRUE(transferer.TransferImage(source->pixel_buffer, destination));
+ // Verify the result has the same number of checker tiles.
+ int num_tiles_across_x;
+ int num_tiles_across_y;
+ std::tie(num_tiles_across_x, num_tiles_across_y) =
+ GetCheckerPatternNumTilesAccross(
+ CreateArgbBufferFromYuvsIOSurface(
+ CVPixelBufferGetIOSurface(destination)),
+ kDestinationWidth, kDestinationHeight);
+ EXPECT_EQ(num_tiles_across_x, kSourceNumTilesAcross);
+ EXPECT_EQ(num_tiles_across_y, kSourceNumTilesAcross);
+}
+
+TEST(PixelBufferTransfererTest, CanStretchYuvsAndVerifyCheckerPattern) {
+ // Note: The ARGB -> YUVS -> ARGB conversions results in a small loss of
+ // information, so for the checker pattern to be intact the buffer can't be
+ // tiny (e.g. 4x4).
+ constexpr int kSourceWidth = 64;
+ constexpr int kSourceHeight = 64;
+ constexpr int kSourceNumTilesAcross = 4;
+ constexpr int kDestinationWidth = 48;
+ constexpr int kDestinationHeight = 32;
+ PixelBufferTransferer transferer;
+ // Source: A single colored buffer.
+ std::unique_ptr<ByteArrayPixelBuffer> source =
+ CreateYuvsPixelBufferFromArgbBuffer(
+ kSourceWidth, kSourceHeight,
+ CreateArgbCheckerPatternBuffer(kSourceWidth, kSourceHeight,
+ kSourceNumTilesAcross));
+ // Destination buffer: A downscaled YUVS buffer.
+ base::ScopedCFTypeRef<CVPixelBufferRef> destination =
+ PixelBufferPool::Create(kPixelFormatYuvs, kDestinationWidth,
+ kDestinationHeight, 1)
+ ->CreateBuffer();
+ EXPECT_TRUE(transferer.TransferImage(source->pixel_buffer, destination));
+ // Verify the result has the same number of checker tiles.
+ int num_tiles_across_x;
+ int num_tiles_across_y;
+ std::tie(num_tiles_across_x, num_tiles_across_y) =
+ GetCheckerPatternNumTilesAccross(
+ CreateArgbBufferFromYuvsIOSurface(
+ CVPixelBufferGetIOSurface(destination)),
+ kDestinationWidth, kDestinationHeight);
+ EXPECT_EQ(num_tiles_across_x, kSourceNumTilesAcross);
+ EXPECT_EQ(num_tiles_across_y, kSourceNumTilesAcross);
+}
+
+TEST(PixelBufferTransfererTest, CanStretchYuvsAndVerifyColor) {
+ constexpr OSType kPixelFormat = kPixelFormatYuvs;
+ constexpr int kSourceWidth = 32;
+ constexpr int kSourceHeight = 32;
+ constexpr int kDestinationWidth = 48; // Aspect ratio does not match source.
+ constexpr int kDestinationHeight = 16;
+ PixelBufferTransferer transferer;
+ // Source: A single colored buffer.
+ std::unique_ptr<ByteArrayPixelBuffer> source =
+ CreateYuvsPixelBufferFromSingleRgbColor(kSourceWidth, kSourceHeight,
+ kColorR, kColorG, kColorB);
+ // Destination buffer: A streched YUVS buffer.
+ base::ScopedCFTypeRef<CVPixelBufferRef> destination =
+ PixelBufferPool::Create(kPixelFormat, kDestinationWidth,
+ kDestinationHeight, 1)
+ ->CreateBuffer();
+ EXPECT_TRUE(transferer.TransferImage(source->pixel_buffer, destination));
+ // Verify the result is the same color.
+ EXPECT_TRUE(YuvsIOSurfaceIsSingleColor(CVPixelBufferGetIOSurface(destination),
+ kColorR, kColorG, kColorB));
+}
+
+TEST(PixelBufferTransfererTest, CanConvertAndStretchSimultaneouslyYuvsToNv12) {
+ // Source pixel format: YUVS
+ constexpr int kSourceWidth = 32;
+ constexpr int kSourceHeight = 32;
+ constexpr OSType kDestinationPixelFormat = kPixelFormatNv12;
+ constexpr int kDestinationWidth = 48; // Aspect ratio does not match source.
+ constexpr int kDestinationHeight = 16;
+ PixelBufferTransferer transferer;
+ // Source: A single colored buffer.
+ std::unique_ptr<ByteArrayPixelBuffer> source =
+ CreateYuvsPixelBufferFromSingleRgbColor(kSourceWidth, kSourceHeight,
+ kColorR, kColorG, kColorB);
+ // Destination buffer: A streched NV12 buffer.
+ base::ScopedCFTypeRef<CVPixelBufferRef> destination =
+ PixelBufferPool::Create(kDestinationPixelFormat, kDestinationWidth,
+ kDestinationHeight, 1)
+ ->CreateBuffer();
+ EXPECT_TRUE(transferer.TransferImage(source->pixel_buffer, destination));
+}
+
+class PixelBufferTransfererParameterizedTest
+ : public ::testing::Test,
+ public ::testing::WithParamInterface<std::tuple<OSType, OSType>> {};
+
+// We do not have the testing utils necessary to create and verify pixel buffers
+// in other formats than YUVS, so in order to test the full conversion matrix of
+// all supported formats X -> Y, this parameterized test performs:
+// YUVS -> X -> Y -> YUVS
+TEST_P(PixelBufferTransfererParameterizedTest,
+ CanConvertFromXToYAndVerifyColor) {
+ OSType pixel_format_from;
+ OSType pixel_format_to;
+ std::tie(pixel_format_from, pixel_format_to) = GetParam();
+ LOG(INFO) << "Running Test: " << MacFourCCToString(pixel_format_from)
+ << " -> " << MacFourCCToString(pixel_format_to);
+
+ constexpr int kWidth = 32;
+ constexpr int kHeight = 32;
+ PixelBufferTransferer transferer;
+ // We always start with YUVS because this is the format that the testing
+ // utilities can convert to/from RGB.
+ std::unique_ptr<ByteArrayPixelBuffer> original_yuvs_buffer =
+ CreateYuvsPixelBufferFromSingleRgbColor(kWidth, kHeight, kColorR, kColorG,
+ kColorB);
+ // YUVS -> pixel_format_from
+ base::ScopedCFTypeRef<CVPixelBufferRef> pixel_buffer_from;
+ if (pixel_format_from == kPixelFormatYuvs) {
+ pixel_buffer_from = original_yuvs_buffer->pixel_buffer;
+ } else {
+ pixel_buffer_from =
+ PixelBufferPool::Create(pixel_format_from, kWidth, kHeight, 1)
+ ->CreateBuffer();
+ transferer.TransferImage(original_yuvs_buffer->pixel_buffer,
+ pixel_buffer_from);
+ }
+ ASSERT_TRUE(pixel_buffer_from);
+
+ // pixel_format_from -> pixel_format_to
+ base::ScopedCFTypeRef<CVPixelBufferRef> pixel_buffer_to =
+ PixelBufferPool::Create(pixel_format_to, kWidth, kHeight, 1)
+ ->CreateBuffer();
+ EXPECT_TRUE(transferer.TransferImage(pixel_buffer_from, pixel_buffer_to));
+
+ // We always convert back to YUVS because this is the only format that the
+ // testing utilities can convert to/from RGB.
+ base::ScopedCFTypeRef<CVPixelBufferRef> final_yuvs_buffer;
+ // pixel_format_to -> YUVS
+ if (pixel_format_to == kPixelFormatYuvs) {
+ final_yuvs_buffer = pixel_buffer_to;
+ } else {
+ final_yuvs_buffer =
+ PixelBufferPool::Create(kPixelFormatYuvs, kWidth, kHeight, 1)
+ ->CreateBuffer();
+ transferer.TransferImage(pixel_buffer_to, final_yuvs_buffer);
+ }
+ ASSERT_TRUE(final_yuvs_buffer);
+ // Verify that after our "conversion dance" we end up with the same color that
+ // we started with.
+ EXPECT_TRUE(YuvsIOSurfaceIsSingleColor(
+ CVPixelBufferGetIOSurface(final_yuvs_buffer), kColorR, kColorG, kColorB));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PixelBufferTransfererTest,
+ PixelBufferTransfererParameterizedTest,
+ ::testing::Combine(::testing::Values(kPixelFormatNv12,
+ kPixelFormatUyvy,
+ kPixelFormatYuvs,
+ kPixelFormatI420),
+ ::testing::Values(kPixelFormatNv12,
+ kPixelFormatUyvy,
+ kPixelFormatYuvs,
+ kPixelFormatI420)));
+
+} // namespace media