blob: 0e99f2da0999e4c92489a9ffd1ba6f45d9f26cf8 [file]
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// #define LOG_NDEBUG 0
#define LOG_TAG "UtilTest"
#include <android_companion_virtualdevice_flags.h>
#include <flag_macros.h>
#include <sys/types.h>
#include <array>
#include <cstdint>
#include <cstring>
#include "aidl/android/companion/virtualcamera/Format.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "system/graphics.h"
#include "util/Util.h"
#include "utils/Errors.h"
namespace android {
namespace companion {
namespace virtualcamera {
namespace {
namespace flags = ::android::companion::virtualdevice::flags;
using ::aidl::android::companion::virtualcamera::Format;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
using ::aidl::android::hardware::camera::device::Stream;
using ::aidl::android::hardware::graphics::common::Dataspace;
using ::aidl::android::hardware::graphics::common::PixelFormat;
using ::testing::Eq;
using ::testing::Gt;
using ::testing::Ne;
using ::testing::Optional;
using ::testing::VariantWith;
const std::array<Format, 5> kImageFormats = {
Format::UNKNOWN, Format::RGBA_8888, Format::YUV_420_888, Format::JPEG,
Format::HEIC,
};
class UtilTest : public ::testing::Test {};
TEST_F(UtilTest, validateSupportedInputImageFormats) {
for (Format f : kImageFormats) {
switch (f) {
case Format::UNKNOWN:
EXPECT_FALSE(isImageFormatSupportedForInput(f));
break;
case Format::RGBA_8888:
[[fallthrough]];
case Format::YUV_420_888:
EXPECT_TRUE(isImageFormatSupportedForInput(f));
break;
case Format::JPEG:
[[fallthrough]];
case Format::HEIC:
EXPECT_EQ(isImageFormatSupportedForInput(f),
flags::virtual_camera_direct_blob_transfer());
break;
}
}
}
TEST_F(UtilTest, IsFormatSupportedForInput_ReturnsTrueForValidNonBlobFormats) {
// Test supported non-blob formats with valid parameters.
EXPECT_TRUE(isFormatSupportedForInput(1920, 1080, Format::YUV_420_888, 30));
EXPECT_TRUE(isFormatSupportedForInput(1280, 720, Format::RGBA_8888, 60));
}
TEST_F(UtilTest, IsFormatSupportedForInput_ReturnsFalseForInvalidWidth) {
EXPECT_FALSE(isFormatSupportedForInput(0, 1080, Format::YUV_420_888, 30));
EXPECT_FALSE(isFormatSupportedForInput(-1, 1080, Format::YUV_420_888, 30));
}
TEST_F(UtilTest, IsFormatSupportedForInput_ReturnsFalseForInvalidHeight) {
EXPECT_FALSE(isFormatSupportedForInput(1920, 0, Format::YUV_420_888, 30));
EXPECT_FALSE(isFormatSupportedForInput(1920, -1, Format::YUV_420_888, 30));
}
TEST_F(UtilTest, IsFormatSupportedForInput_ReturnsFalseForInvalidFps) {
EXPECT_FALSE(isFormatSupportedForInput(1920, 1080, Format::YUV_420_888, 0));
EXPECT_FALSE(isFormatSupportedForInput(1920, 1080, Format::YUV_420_888, -10));
EXPECT_FALSE(isFormatSupportedForInput(1920, 1080, Format::YUV_420_888, 61));
}
TEST_F(UtilTest, IsFormatSupportedForInput_ReturnsFalseForUnknownFormat) {
EXPECT_FALSE(isFormatSupportedForInput(1920, 1080, Format::UNKNOWN, 30));
}
TEST_F_WITH_FLAGS(
UtilTest, IsFormatSupportedForInput_BlobFormatSupportedWhenFlagEnabled,
REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(
android::companion::virtualdevice::flags, virtual_camera_direct_blob_transfer))) {
EXPECT_TRUE(isFormatSupportedForInput(800, 600, Format::JPEG, 30));
EXPECT_TRUE(isFormatSupportedForInput(1024, 768, Format::HEIC, 30));
}
TEST_F_WITH_FLAGS(
UtilTest, IsFormatSupportedForInput_BlobFormatUnsupportedWhenFlagDisabled,
REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(
android::companion::virtualdevice::flags, virtual_camera_direct_blob_transfer))) {
EXPECT_FALSE(isFormatSupportedForInput(800, 600, Format::JPEG, 30));
EXPECT_FALSE(isFormatSupportedForInput(1024, 768, Format::HEIC, 30));
}
TEST_F(
UtilTest,
IsFormatSupportedForInput_ReturnsFalseForBlobFormatsWithInvalidParameters) {
// Blob formats with invalid parameters should always be unsupported,
// regardless of the feature flag.
// Invalid width with JPEG format.
EXPECT_FALSE(isFormatSupportedForInput(0, 600, Format::JPEG, 30));
// Invalid height with JPEG format.
EXPECT_FALSE(isFormatSupportedForInput(800, 0, Format::JPEG, 30));
// Invalid fps with JPEG format.
EXPECT_FALSE(isFormatSupportedForInput(800, 600, Format::JPEG, 0));
EXPECT_FALSE(isFormatSupportedForInput(800, 600, Format::JPEG, 61));
}
TEST_F(UtilTest, isBlobFormatTest) {
for (Format f : kImageFormats) {
switch (f) {
case Format::UNKNOWN:
[[fallthrough]];
case Format::RGBA_8888:
[[fallthrough]];
case Format::YUV_420_888:
EXPECT_FALSE(isBlobFormat(f));
break;
case Format::JPEG:
[[fallthrough]];
case Format::HEIC:
EXPECT_TRUE(isBlobFormat(f));
break;
}
}
}
TEST_F(UtilTest, isBlobStreamConfigTest) {
Stream stream;
// Check supported BLOB types
stream.format = PixelFormat::BLOB;
stream.dataSpace = Dataspace::HEIF;
EXPECT_TRUE(isBlobStreamConfig(stream));
stream.dataSpace = Dataspace::JFIF;
EXPECT_TRUE(isBlobStreamConfig(stream));
// Check unsupported BLOB types
stream.dataSpace = Dataspace::JPEG_R;
EXPECT_FALSE(isBlobStreamConfig(stream));
// Check malformed streams
stream.dataSpace = Dataspace::JFIF;
stream.format = PixelFormat::YCBCR_420_888;
EXPECT_FALSE(isBlobStreamConfig(stream));
stream.format = PixelFormat::RGBA_8888;
EXPECT_FALSE(isBlobStreamConfig(stream));
// Check legal uncompressed streams
stream.dataSpace = Dataspace::UNKNOWN;
EXPECT_FALSE(isBlobStreamConfig(stream));
stream.format = PixelFormat::YCBCR_420_888;
EXPECT_FALSE(isBlobStreamConfig(stream));
}
TEST_F(UtilTest, areMatchingBlobTypesTest) {
Stream halStream;
SupportedStreamConfiguration inputConfig;
// Test matching HEIC types
halStream.format = PixelFormat::BLOB;
halStream.dataSpace = Dataspace::HEIF;
inputConfig.imageFormat = Format::HEIC;
EXPECT_TRUE(areMatchingBlobTypes(halStream, inputConfig));
// Test mis-matching blob types
halStream.dataSpace = Dataspace::JFIF;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
halStream.dataSpace = Dataspace::HEIF;
inputConfig.imageFormat = Format::JPEG;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
// Test matching JPEG types
halStream.dataSpace = Dataspace::JFIF;
EXPECT_TRUE(areMatchingBlobTypes(halStream, inputConfig));
// Test mis-matching blob and scaler types
inputConfig.imageFormat = Format::YUV_420_888;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
inputConfig.imageFormat = Format::RGBA_8888;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
inputConfig.imageFormat = Format::UNKNOWN;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
halStream.dataSpace = Dataspace::HEIF;
inputConfig.imageFormat = Format::YUV_420_888;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
inputConfig.imageFormat = Format::RGBA_8888;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
inputConfig.imageFormat = Format::UNKNOWN;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
// Test matching scaler types. Expect fail since not blob
inputConfig.imageFormat = Format::YUV_420_888;
halStream.format = PixelFormat::YCRCB_420_SP;
halStream.dataSpace = Dataspace::UNKNOWN;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
inputConfig.imageFormat = Format::RGBA_8888;
halStream.format = PixelFormat::RGBA_8888;
EXPECT_FALSE(areMatchingBlobTypes(halStream, inputConfig));
}
TEST_F(UtilTest, areMatchingBlobFormatsTest) {
EXPECT_TRUE(areMatchingBlobTypes(Format::HEIC, Format::HEIC));
EXPECT_TRUE(areMatchingBlobTypes(Format::JPEG, Format::JPEG));
EXPECT_FALSE(areMatchingBlobTypes(Format::JPEG, Format::HEIC));
EXPECT_FALSE(areMatchingBlobTypes(Format::JPEG, Format::YUV_420_888));
EXPECT_FALSE(areMatchingBlobTypes(Format::JPEG, Format::RGBA_8888));
EXPECT_FALSE(areMatchingBlobTypes(Format::JPEG, Format::UNKNOWN));
EXPECT_FALSE(areMatchingBlobTypes(Format::HEIC, Format::YUV_420_888));
EXPECT_FALSE(areMatchingBlobTypes(Format::HEIC, Format::RGBA_8888));
EXPECT_FALSE(areMatchingBlobTypes(Format::HEIC, Format::UNKNOWN));
}
TEST_F(UtilTest, areDifferentBlobFormatsTest) {
EXPECT_TRUE(areDifferentBlobTypes(Format::HEIC, Format::JPEG));
EXPECT_FALSE(areDifferentBlobTypes(Format::HEIC, Format::HEIC));
EXPECT_FALSE(areDifferentBlobTypes(Format::JPEG, Format::JPEG));
EXPECT_FALSE(areDifferentBlobTypes(Format::JPEG, Format::YUV_420_888));
EXPECT_FALSE(areDifferentBlobTypes(Format::JPEG, Format::RGBA_8888));
EXPECT_FALSE(areDifferentBlobTypes(Format::JPEG, Format::UNKNOWN));
EXPECT_FALSE(areDifferentBlobTypes(Format::HEIC, Format::YUV_420_888));
EXPECT_FALSE(areDifferentBlobTypes(Format::HEIC, Format::RGBA_8888));
EXPECT_FALSE(areDifferentBlobTypes(Format::HEIC, Format::UNKNOWN));
}
} // namespace
} // namespace virtualcamera
} // namespace companion
} // namespace android