blob: 9146d8a3e659ed1bd6ad57c34162a4ae89889ba1 [file] [log] [blame]
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +01001/*
Biswarup Pal6152a302023-12-19 12:44:09 +00002 * Copyright 2023 The Android Open Source Project
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +01003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +010017#include <algorithm>
18#include <iterator>
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010019#include <memory>
20
21#include "VirtualCameraDevice.h"
22#include "aidl/android/companion/virtualcamera/Format.h"
23#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
Biswarup Pal6152a302023-12-19 12:44:09 +000024#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010025#include "aidl/android/hardware/camera/device/CameraMetadata.h"
26#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +010027#include "aidl/android/hardware/graphics/common/PixelFormat.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010028#include "android/binder_interface_utils.h"
29#include "gmock/gmock.h"
30#include "gtest/gtest.h"
31#include "log/log_main.h"
32#include "system/camera_metadata.h"
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +010033#include "util/MetadataUtil.h"
34#include "util/Util.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010035#include "utils/Errors.h"
36
37namespace android {
38namespace companion {
39namespace virtualcamera {
40namespace {
41
42using ::aidl::android::companion::virtualcamera::Format;
Biswarup Pal112458f2023-12-28 19:50:17 +000043using ::aidl::android::companion::virtualcamera::LensFacing;
Biswarup Pal6152a302023-12-19 12:44:09 +000044using ::aidl::android::companion::virtualcamera::SensorOrientation;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010045using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Biswarup Pal6152a302023-12-19 12:44:09 +000046using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010047using ::aidl::android::hardware::camera::device::CameraMetadata;
48using ::aidl::android::hardware::camera::device::Stream;
49using ::aidl::android::hardware::camera::device::StreamConfiguration;
50using ::aidl::android::hardware::camera::device::StreamType;
51using ::aidl::android::hardware::graphics::common::PixelFormat;
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +010052using ::testing::ElementsAre;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010053using ::testing::UnorderedElementsAreArray;
54using metadata_stream_t =
55 camera_metadata_enum_android_scaler_available_stream_configurations_t;
56
57constexpr int kCameraId = 42;
58constexpr int kVgaWidth = 640;
59constexpr int kVgaHeight = 480;
60constexpr int kHdWidth = 1280;
61constexpr int kHdHeight = 720;
Biswarup Pal6152a302023-12-19 12:44:09 +000062constexpr int kMaxFps = 30;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010063
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +010064const Stream kVgaYUV420Stream = Stream{
65 .streamType = StreamType::OUTPUT,
66 .width = kVgaWidth,
67 .height = kVgaHeight,
68 .format = PixelFormat::YCBCR_420_888,
69};
70
71const Stream kVgaJpegStream = Stream{
72 .streamType = StreamType::OUTPUT,
73 .width = kVgaWidth,
74 .height = kVgaHeight,
75 .format = PixelFormat::BLOB,
76};
77
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010078struct AvailableStreamConfiguration {
79 const int width;
80 const int height;
81 const int pixelFormat;
82 const metadata_stream_t streamConfiguration;
83};
84
85bool operator==(const AvailableStreamConfiguration& a,
86 const AvailableStreamConfiguration& b) {
87 return a.width == b.width && a.height == b.height &&
88 a.pixelFormat == b.pixelFormat &&
89 a.streamConfiguration == b.streamConfiguration;
90}
91
92std::ostream& operator<<(std::ostream& os,
93 const AvailableStreamConfiguration& config) {
94 os << config.width << "x" << config.height << " (pixfmt "
95 << config.pixelFormat << ", streamConfiguration "
96 << config.streamConfiguration << ")";
97 return os;
98}
99
100std::vector<AvailableStreamConfiguration> getAvailableStreamConfigurations(
101 const CameraMetadata& metadata) {
102 const camera_metadata_t* const raw =
103 reinterpret_cast<const camera_metadata_t*>(metadata.metadata.data());
104 camera_metadata_ro_entry_t entry;
105 if (find_camera_metadata_ro_entry(
106 raw, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry) !=
107 NO_ERROR) {
108 return {};
109 }
110
111 std::vector<AvailableStreamConfiguration> res;
112 for (int i = 0; i < entry.count; i += 4) {
113 res.push_back(AvailableStreamConfiguration{
114 .width = entry.data.i32[i + 1],
115 .height = entry.data.i32[i + 2],
116 .pixelFormat = entry.data.i32[i],
117 .streamConfiguration =
118 static_cast<metadata_stream_t>(entry.data.i32[i + 3])});
119 }
120 return res;
121}
122
123struct VirtualCameraConfigTestParam {
Biswarup Pal6152a302023-12-19 12:44:09 +0000124 VirtualCameraConfiguration inputConfig;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100125 std::vector<AvailableStreamConfiguration> expectedAvailableStreamConfigs;
126};
127
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100128class VirtualCameraDeviceCharacterisicsTest
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100129 : public testing::TestWithParam<VirtualCameraConfigTestParam> {};
130
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100131TEST_P(VirtualCameraDeviceCharacterisicsTest,
132 cameraCharacteristicsForInputFormat) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100133 const VirtualCameraConfigTestParam& param = GetParam();
134 std::shared_ptr<VirtualCameraDevice> camera =
Biswarup Pal6152a302023-12-19 12:44:09 +0000135 ndk::SharedRefBase::make<VirtualCameraDevice>(kCameraId,
136 param.inputConfig);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100137
138 CameraMetadata metadata;
139 ASSERT_TRUE(camera->getCameraCharacteristics(&metadata).isOk());
140 EXPECT_THAT(getAvailableStreamConfigurations(metadata),
141 UnorderedElementsAreArray(param.expectedAvailableStreamConfigs));
142
143 // Configuration needs to succeed for every available stream configuration
144 for (const AvailableStreamConfiguration& config :
145 param.expectedAvailableStreamConfigs) {
146 StreamConfiguration configuration{
147 .streams = std::vector<Stream>{Stream{
148 .streamType = StreamType::OUTPUT,
149 .width = config.width,
150 .height = config.height,
151 .format = static_cast<PixelFormat>(config.pixelFormat),
152 }}};
153 bool aidl_ret;
154 ASSERT_TRUE(
155 camera->isStreamCombinationSupported(configuration, &aidl_ret).isOk());
156 EXPECT_TRUE(aidl_ret);
157 }
158}
159
160INSTANTIATE_TEST_SUITE_P(
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100161 cameraCharacteristicsForInputFormat, VirtualCameraDeviceCharacterisicsTest,
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100162 testing::Values(
163 VirtualCameraConfigTestParam{
Biswarup Pal6152a302023-12-19 12:44:09 +0000164 .inputConfig =
165 VirtualCameraConfiguration{
166 .supportedStreamConfigs = {SupportedStreamConfiguration{
167 .width = kVgaWidth,
168 .height = kVgaHeight,
169 .pixelFormat = Format::YUV_420_888,
170 .maxFps = kMaxFps}},
171 .virtualCameraCallback = nullptr,
Biswarup Pal112458f2023-12-28 19:50:17 +0000172 .sensorOrientation = SensorOrientation::ORIENTATION_0,
173 .lensFacing = LensFacing::FRONT},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100174 .expectedAvailableStreamConfigs =
175 {AvailableStreamConfiguration{
176 .width = kVgaWidth,
177 .height = kVgaHeight,
178 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
179 .streamConfiguration =
180 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
181 AvailableStreamConfiguration{
182 .width = kVgaWidth,
183 .height = kVgaHeight,
184 .pixelFormat =
185 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
186 .streamConfiguration =
187 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
188 AvailableStreamConfiguration{
189 .width = kVgaWidth,
190 .height = kVgaHeight,
191 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
192 .streamConfiguration =
193 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}}},
194 VirtualCameraConfigTestParam{
Biswarup Pal6152a302023-12-19 12:44:09 +0000195 .inputConfig =
196 VirtualCameraConfiguration{
197 .supportedStreamConfigs =
198 {SupportedStreamConfiguration{
199 .width = kVgaWidth,
200 .height = kVgaHeight,
201 .pixelFormat = Format::YUV_420_888,
202 .maxFps = kMaxFps},
203 SupportedStreamConfiguration{
204 .width = kHdWidth,
205 .height = kHdHeight,
206 .pixelFormat = Format::YUV_420_888,
207 .maxFps = kMaxFps}},
208 .virtualCameraCallback = nullptr,
Biswarup Pal112458f2023-12-28 19:50:17 +0000209 .sensorOrientation = SensorOrientation::ORIENTATION_0,
210 .lensFacing = LensFacing::BACK},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100211 .expectedAvailableStreamConfigs = {
212 AvailableStreamConfiguration{
213 .width = kVgaWidth,
214 .height = kVgaHeight,
215 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
216 .streamConfiguration =
217 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
218 AvailableStreamConfiguration{
219 .width = kVgaWidth,
220 .height = kVgaHeight,
221 .pixelFormat =
222 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
223 .streamConfiguration =
224 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
225 AvailableStreamConfiguration{
226 .width = kVgaWidth,
227 .height = kVgaHeight,
228 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
229 .streamConfiguration =
230 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
231 AvailableStreamConfiguration{
232 .width = kHdWidth,
233 .height = kHdHeight,
234 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
235 .streamConfiguration =
236 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
237 AvailableStreamConfiguration{
238 .width = kHdWidth,
239 .height = kHdHeight,
240 .pixelFormat =
241 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
242 .streamConfiguration =
243 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
244 AvailableStreamConfiguration{
245 .width = kHdWidth,
246 .height = kHdHeight,
247 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
248 .streamConfiguration =
249 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}}}));
250
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100251class VirtualCameraDeviceTest : public ::testing::Test {
252 public:
253 void SetUp() override {
254 mCamera = ndk::SharedRefBase::make<VirtualCameraDevice>(
255 kCameraId, VirtualCameraConfiguration{
256 .supportedStreamConfigs = {SupportedStreamConfiguration{
257 .width = kVgaWidth,
258 .height = kVgaHeight,
259 .pixelFormat = Format::YUV_420_888,
260 .maxFps = kMaxFps}},
261 .virtualCameraCallback = nullptr,
262 .sensorOrientation = SensorOrientation::ORIENTATION_0,
263 .lensFacing = LensFacing::FRONT});
264 }
265
266 protected:
267 std::shared_ptr<VirtualCameraDevice> mCamera;
268};
269
270TEST_F(VirtualCameraDeviceTest, configureMaximalNumberOfNonStallStreamsSuceeds) {
271 StreamConfiguration config;
272 std::fill_n(std::back_insert_iterator(config.streams),
273 VirtualCameraDevice::kMaxNumberOfProcessedStreams,
274 kVgaYUV420Stream);
275
276 bool aidl_ret;
277 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
278 EXPECT_TRUE(aidl_ret);
279}
280
281TEST_F(VirtualCameraDeviceTest, configureTooManyNonStallStreamsFails) {
282 StreamConfiguration config;
283 std::fill_n(std::back_insert_iterator(config.streams),
284 VirtualCameraDevice::kMaxNumberOfProcessedStreams + 1,
285 kVgaYUV420Stream);
286
287 bool aidl_ret;
288 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
289 EXPECT_FALSE(aidl_ret);
290}
291
292TEST_F(VirtualCameraDeviceTest, configureMaximalNumberOfStallStreamsSuceeds) {
293 StreamConfiguration config;
294 std::fill_n(std::back_insert_iterator(config.streams),
295 VirtualCameraDevice::kMaxNumberOfStallStreams, kVgaJpegStream);
296
297 bool aidl_ret;
298 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
299 EXPECT_TRUE(aidl_ret);
300}
301
302TEST_F(VirtualCameraDeviceTest, configureTooManyStallStreamsFails) {
303 StreamConfiguration config;
304 std::fill_n(std::back_insert_iterator(config.streams),
305 VirtualCameraDevice::kMaxNumberOfStallStreams + 1, kVgaJpegStream);
306
307 bool aidl_ret;
308 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
309 EXPECT_FALSE(aidl_ret);
310}
311
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100312TEST_F(VirtualCameraDeviceTest, thumbnailSizeWithCompatibleAspectRatio) {
313 CameraMetadata metadata;
314 ASSERT_TRUE(mCamera->getCameraCharacteristics(&metadata).isOk());
315
316 // Camera is configured with VGA input, we expect 240 x 180 thumbnail size in
317 // characteristics, since it has same aspect ratio.
318 EXPECT_THAT(getJpegAvailableThumbnailSizes(metadata),
319 ElementsAre(Resolution(0, 0), Resolution(240, 180)));
320}
321
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100322} // namespace
323} // namespace virtualcamera
324} // namespace companion
325} // namespace android