1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
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
17 #include <algorithm>
18 #include <iterator>
19 #include <memory>
20
21 #include "VirtualCameraDevice.h"
22 #include "aidl/android/companion/virtualcamera/Format.h"
23 #include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
24 #include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
25 #include "aidl/android/hardware/camera/device/CameraMetadata.h"
26 #include "aidl/android/hardware/camera/device/StreamConfiguration.h"
27 #include "aidl/android/hardware/graphics/common/PixelFormat.h"
28 #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"
33 #include "util/MetadataUtil.h"
34 #include "util/Util.h"
35 #include "utils/Errors.h"
36
37 namespace android {
38 namespace companion {
39 namespace virtualcamera {
40 namespace {
41
42 using ::aidl::android::companion::virtualcamera::Format;
43 using ::aidl::android::companion::virtualcamera::LensFacing;
44 using ::aidl::android::companion::virtualcamera::SensorOrientation;
45 using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
46 using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
47 using ::aidl::android::hardware::camera::device::CameraMetadata;
48 using ::aidl::android::hardware::camera::device::Stream;
49 using ::aidl::android::hardware::camera::device::StreamConfiguration;
50 using ::aidl::android::hardware::camera::device::StreamType;
51 using ::aidl::android::hardware::graphics::common::PixelFormat;
52 using ::testing::ElementsAre;
53 using ::testing::UnorderedElementsAreArray;
54 using metadata_stream_t =
55 camera_metadata_enum_android_scaler_available_stream_configurations_t;
56
57 constexpr char kCameraId[] = "42";
58 constexpr int kQvgaWidth = 320;
59 constexpr int kQvgaHeight = 240;
60 constexpr int kVgaWidth = 640;
61 constexpr int kVgaHeight = 480;
62 constexpr int kHdWidth = 1280;
63 constexpr int kHdHeight = 720;
64 constexpr int kMaxFps = 30;
65 constexpr int kDefaultDeviceId = 0;
66
67 const Stream kVgaYUV420Stream = Stream{
68 .streamType = StreamType::OUTPUT,
69 .width = kVgaWidth,
70 .height = kVgaHeight,
71 .format = PixelFormat::YCBCR_420_888,
72 };
73
74 const Stream kVgaJpegStream = Stream{
75 .streamType = StreamType::OUTPUT,
76 .width = kVgaWidth,
77 .height = kVgaHeight,
78 .format = PixelFormat::BLOB,
79 };
80
81 struct AvailableStreamConfiguration {
82 const int width;
83 const int height;
84 const int pixelFormat;
85 const metadata_stream_t streamConfiguration =
86 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
87 };
88
operator ==(const AvailableStreamConfiguration & a,const AvailableStreamConfiguration & b)89 bool operator==(const AvailableStreamConfiguration& a,
90 const AvailableStreamConfiguration& b) {
91 return a.width == b.width && a.height == b.height &&
92 a.pixelFormat == b.pixelFormat &&
93 a.streamConfiguration == b.streamConfiguration;
94 }
95
operator <<(std::ostream & os,const AvailableStreamConfiguration & config)96 std::ostream& operator<<(std::ostream& os,
97 const AvailableStreamConfiguration& config) {
98 os << config.width << "x" << config.height << " (pixfmt "
99 << config.pixelFormat << ", streamConfiguration "
100 << config.streamConfiguration << ")";
101 return os;
102 }
103
getAvailableStreamConfigurations(const CameraMetadata & metadata)104 std::vector<AvailableStreamConfiguration> getAvailableStreamConfigurations(
105 const CameraMetadata& metadata) {
106 const camera_metadata_t* const raw =
107 reinterpret_cast<const camera_metadata_t*>(metadata.metadata.data());
108 camera_metadata_ro_entry_t entry;
109 if (find_camera_metadata_ro_entry(
110 raw, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry) !=
111 NO_ERROR) {
112 return {};
113 }
114
115 std::vector<AvailableStreamConfiguration> res;
116 for (int i = 0; i < entry.count; i += 4) {
117 res.push_back(AvailableStreamConfiguration{
118 .width = entry.data.i32[i + 1],
119 .height = entry.data.i32[i + 2],
120 .pixelFormat = entry.data.i32[i],
121 .streamConfiguration =
122 static_cast<metadata_stream_t>(entry.data.i32[i + 3])});
123 }
124 return res;
125 }
126
127 struct VirtualCameraConfigTestParam {
128 VirtualCameraConfiguration inputConfig;
129 std::vector<AvailableStreamConfiguration> expectedAvailableStreamConfigs;
130 };
131
132 class VirtualCameraDeviceCharacterisicsTest
133 : public testing::TestWithParam<VirtualCameraConfigTestParam> {};
134
TEST_P(VirtualCameraDeviceCharacterisicsTest,cameraCharacteristicsForInputFormat)135 TEST_P(VirtualCameraDeviceCharacterisicsTest,
136 cameraCharacteristicsForInputFormat) {
137 const VirtualCameraConfigTestParam& param = GetParam();
138 std::shared_ptr<VirtualCameraDevice> camera =
139 ndk::SharedRefBase::make<VirtualCameraDevice>(
140 kCameraId, param.inputConfig, kDefaultDeviceId);
141
142 CameraMetadata metadata;
143 ASSERT_TRUE(camera->getCameraCharacteristics(&metadata).isOk());
144 EXPECT_THAT(getAvailableStreamConfigurations(metadata),
145 UnorderedElementsAreArray(param.expectedAvailableStreamConfigs));
146
147 // Configuration needs to succeed for every available stream configuration
148 for (const AvailableStreamConfiguration& config :
149 param.expectedAvailableStreamConfigs) {
150 StreamConfiguration configuration{
151 .streams = std::vector<Stream>{Stream{
152 .streamType = StreamType::OUTPUT,
153 .width = config.width,
154 .height = config.height,
155 .format = static_cast<PixelFormat>(config.pixelFormat),
156 }}};
157 bool aidl_ret;
158 ASSERT_TRUE(
159 camera->isStreamCombinationSupported(configuration, &aidl_ret).isOk());
160 EXPECT_TRUE(aidl_ret);
161 }
162 }
163
164 INSTANTIATE_TEST_SUITE_P(
165 cameraCharacteristicsForInputFormat, VirtualCameraDeviceCharacterisicsTest,
166 testing::Values(
167 VirtualCameraConfigTestParam{
168 .inputConfig =
169 VirtualCameraConfiguration{
170 .supportedStreamConfigs = {SupportedStreamConfiguration{
171 .width = kVgaWidth,
172 .height = kVgaHeight,
173 .pixelFormat = Format::YUV_420_888,
174 .maxFps = kMaxFps}},
175 .virtualCameraCallback = nullptr,
176 .sensorOrientation = SensorOrientation::ORIENTATION_0,
177 .lensFacing = LensFacing::FRONT},
178 .expectedAvailableStreamConfigs =
179 {AvailableStreamConfiguration{
180 .width = kQvgaWidth,
181 .height = kQvgaHeight,
182 .pixelFormat =
183 ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
184 AvailableStreamConfiguration{
185 .width = kQvgaWidth,
186 .height = kQvgaHeight,
187 .pixelFormat =
188 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
189 AvailableStreamConfiguration{
190 .width = kQvgaWidth,
191 .height = kQvgaHeight,
192 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
193 AvailableStreamConfiguration{
194 .width = kVgaWidth,
195 .height = kVgaHeight,
196 .pixelFormat =
197 ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
198 AvailableStreamConfiguration{
199 .width = kVgaWidth,
200 .height = kVgaHeight,
201 .pixelFormat =
202 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
203 AvailableStreamConfiguration{
204 .width = kVgaWidth,
205 .height = kVgaHeight,
206 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB}}},
207 VirtualCameraConfigTestParam{
208 .inputConfig =
209 VirtualCameraConfiguration{
210 .supportedStreamConfigs =
211 {SupportedStreamConfiguration{
212 .width = kVgaWidth,
213 .height = kVgaHeight,
214 .pixelFormat = Format::YUV_420_888,
215 .maxFps = kMaxFps},
216 SupportedStreamConfiguration{
217 .width = kHdWidth,
218 .height = kHdHeight,
219 .pixelFormat = Format::YUV_420_888,
220 .maxFps = kMaxFps}},
221 .virtualCameraCallback = nullptr,
222 .sensorOrientation = SensorOrientation::ORIENTATION_0,
223 .lensFacing = LensFacing::BACK},
224 .expectedAvailableStreamConfigs = {
225 AvailableStreamConfiguration{
226 .width = kQvgaWidth,
227 .height = kQvgaHeight,
228 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
229 AvailableStreamConfiguration{
230 .width = kQvgaWidth,
231 .height = kQvgaHeight,
232 .pixelFormat =
233 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
234 AvailableStreamConfiguration{
235 .width = kQvgaWidth,
236 .height = kQvgaHeight,
237 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
238 AvailableStreamConfiguration{
239 .width = 640,
240 .height = 360,
241 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
242 AvailableStreamConfiguration{
243 .width = 640,
244 .height = 360,
245 .pixelFormat =
246 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
247 AvailableStreamConfiguration{
248 .width = 640,
249 .height = 360,
250 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
251 AvailableStreamConfiguration{
252 .width = kVgaWidth,
253 .height = kVgaHeight,
254 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
255 AvailableStreamConfiguration{
256 .width = kVgaWidth,
257 .height = kVgaHeight,
258 .pixelFormat =
259 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
260 AvailableStreamConfiguration{
261 .width = kVgaWidth,
262 .height = kVgaHeight,
263 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
264 AvailableStreamConfiguration{
265 .width = 1024,
266 .height = 576,
267 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
268 AvailableStreamConfiguration{
269 .width = 1024,
270 .height = 576,
271 .pixelFormat =
272 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
273 AvailableStreamConfiguration{
274 .width = 1024,
275 .height = 576,
276 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
277 AvailableStreamConfiguration{
278 .width = kHdWidth,
279 .height = kHdHeight,
280 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
281 AvailableStreamConfiguration{
282 .width = kHdWidth,
283 .height = kHdHeight,
284 .pixelFormat =
285 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
286 AvailableStreamConfiguration{
287 .width = kHdWidth,
288 .height = kHdHeight,
289 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB}}}));
290
291 class VirtualCameraDeviceTest : public ::testing::Test {
292 public:
SetUp()293 void SetUp() override {
294 mCamera = ndk::SharedRefBase::make<VirtualCameraDevice>(
295 kCameraId,
296 VirtualCameraConfiguration{
297 .supportedStreamConfigs = {SupportedStreamConfiguration{
298 .width = kVgaWidth,
299 .height = kVgaHeight,
300 .pixelFormat = Format::YUV_420_888,
301 .maxFps = kMaxFps}},
302 .virtualCameraCallback = nullptr,
303 .sensorOrientation = SensorOrientation::ORIENTATION_0,
304 .lensFacing = LensFacing::FRONT},
305 kDefaultDeviceId);
306 }
307
308 protected:
309 std::shared_ptr<VirtualCameraDevice> mCamera;
310 };
311
TEST_F(VirtualCameraDeviceTest,configureMaximalNumberOfNonStallStreamsSuceeds)312 TEST_F(VirtualCameraDeviceTest, configureMaximalNumberOfNonStallStreamsSuceeds) {
313 StreamConfiguration config;
314 std::fill_n(std::back_insert_iterator(config.streams),
315 VirtualCameraDevice::kMaxNumberOfProcessedStreams,
316 kVgaYUV420Stream);
317
318 bool aidl_ret;
319 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
320 EXPECT_TRUE(aidl_ret);
321 }
322
TEST_F(VirtualCameraDeviceTest,configureTooManyNonStallStreamsFails)323 TEST_F(VirtualCameraDeviceTest, configureTooManyNonStallStreamsFails) {
324 StreamConfiguration config;
325 std::fill_n(std::back_insert_iterator(config.streams),
326 VirtualCameraDevice::kMaxNumberOfProcessedStreams + 1,
327 kVgaYUV420Stream);
328
329 bool aidl_ret;
330 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
331 EXPECT_FALSE(aidl_ret);
332 }
333
TEST_F(VirtualCameraDeviceTest,configureMaximalNumberOfStallStreamsSuceeds)334 TEST_F(VirtualCameraDeviceTest, configureMaximalNumberOfStallStreamsSuceeds) {
335 StreamConfiguration config;
336 std::fill_n(std::back_insert_iterator(config.streams),
337 VirtualCameraDevice::kMaxNumberOfStallStreams, kVgaJpegStream);
338
339 bool aidl_ret;
340 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
341 EXPECT_TRUE(aidl_ret);
342 }
343
TEST_F(VirtualCameraDeviceTest,configureTooManyStallStreamsFails)344 TEST_F(VirtualCameraDeviceTest, configureTooManyStallStreamsFails) {
345 StreamConfiguration config;
346 std::fill_n(std::back_insert_iterator(config.streams),
347 VirtualCameraDevice::kMaxNumberOfStallStreams + 1, kVgaJpegStream);
348
349 bool aidl_ret;
350 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
351 EXPECT_FALSE(aidl_ret);
352 }
353
TEST_F(VirtualCameraDeviceTest,thumbnailSizeWithCompatibleAspectRatio)354 TEST_F(VirtualCameraDeviceTest, thumbnailSizeWithCompatibleAspectRatio) {
355 CameraMetadata metadata;
356 ASSERT_TRUE(mCamera->getCameraCharacteristics(&metadata).isOk());
357
358 // Camera is configured with VGA input, we expect 240 x 180 thumbnail size in
359 // characteristics, since it has same aspect ratio.
360 EXPECT_THAT(getJpegAvailableThumbnailSizes(metadata),
361 ElementsAre(Resolution(0, 0), Resolution(240, 180)));
362 }
363
TEST_F(VirtualCameraDeviceTest,dump)364 TEST_F(VirtualCameraDeviceTest, dump) {
365 std::string expected = R"( virtual_camera 42 belongs to virtual device 0
366 SupportedStreamConfiguration:
367 SupportedStreamConfiguration{width: 640, height: 480, pixelFormat: YUV_420_888, maxFps: 30})";
368 int expectedSize = expected.size() * sizeof(char);
369 char buffer[expectedSize];
370
371 // Create an in memory fd
372 int fd = memfd_create("tmpFile", 0);
373 mCamera->dump(fd, {}, 0);
374
375 // Check that we wrote the expected size
376 int dumpSize = lseek(fd, 0, SEEK_END);
377
378 // Rewind and read from the fd
379 lseek(fd, 0, SEEK_SET);
380 read(fd, buffer, expectedSize);
381 close(fd);
382
383 // Check the content of the dump
384 std::string name = std::string(buffer, expectedSize);
385 ASSERT_EQ(expected, name);
386 // Check the size after the content to display the string mismatch when a
387 // failure occurs
388 ASSERT_EQ(expectedSize, dumpSize);
389 }
390
391 } // namespace
392 } // namespace virtualcamera
393 } // namespace companion
394 } // namespace android
395