diff options
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.mm | 268 |
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 |