blob: ad9d83b0a8cee215f0b0dffcc54879112cbf2a0a [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;
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +010058constexpr int kQvgaWidth = 320;
59constexpr int kQvgaHeight = 240;
60constexpr int k360pWidth = 640;
61constexpr int k360pHeight = 360;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010062constexpr int kVgaWidth = 640;
63constexpr int kVgaHeight = 480;
64constexpr int kHdWidth = 1280;
65constexpr int kHdHeight = 720;
Biswarup Pal6152a302023-12-19 12:44:09 +000066constexpr int kMaxFps = 30;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010067
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +010068const Stream kVgaYUV420Stream = Stream{
69 .streamType = StreamType::OUTPUT,
70 .width = kVgaWidth,
71 .height = kVgaHeight,
72 .format = PixelFormat::YCBCR_420_888,
73};
74
75const Stream kVgaJpegStream = Stream{
76 .streamType = StreamType::OUTPUT,
77 .width = kVgaWidth,
78 .height = kVgaHeight,
79 .format = PixelFormat::BLOB,
80};
81
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010082struct AvailableStreamConfiguration {
83 const int width;
84 const int height;
85 const int pixelFormat;
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +010086 const metadata_stream_t streamConfiguration =
87 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010088};
89
90bool operator==(const AvailableStreamConfiguration& a,
91 const AvailableStreamConfiguration& b) {
92 return a.width == b.width && a.height == b.height &&
93 a.pixelFormat == b.pixelFormat &&
94 a.streamConfiguration == b.streamConfiguration;
95}
96
97std::ostream& operator<<(std::ostream& os,
98 const AvailableStreamConfiguration& config) {
99 os << config.width << "x" << config.height << " (pixfmt "
100 << config.pixelFormat << ", streamConfiguration "
101 << config.streamConfiguration << ")";
102 return os;
103}
104
105std::vector<AvailableStreamConfiguration> getAvailableStreamConfigurations(
106 const CameraMetadata& metadata) {
107 const camera_metadata_t* const raw =
108 reinterpret_cast<const camera_metadata_t*>(metadata.metadata.data());
109 camera_metadata_ro_entry_t entry;
110 if (find_camera_metadata_ro_entry(
111 raw, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry) !=
112 NO_ERROR) {
113 return {};
114 }
115
116 std::vector<AvailableStreamConfiguration> res;
117 for (int i = 0; i < entry.count; i += 4) {
118 res.push_back(AvailableStreamConfiguration{
119 .width = entry.data.i32[i + 1],
120 .height = entry.data.i32[i + 2],
121 .pixelFormat = entry.data.i32[i],
122 .streamConfiguration =
123 static_cast<metadata_stream_t>(entry.data.i32[i + 3])});
124 }
125 return res;
126}
127
128struct VirtualCameraConfigTestParam {
Biswarup Pal6152a302023-12-19 12:44:09 +0000129 VirtualCameraConfiguration inputConfig;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100130 std::vector<AvailableStreamConfiguration> expectedAvailableStreamConfigs;
131};
132
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100133class VirtualCameraDeviceCharacterisicsTest
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100134 : public testing::TestWithParam<VirtualCameraConfigTestParam> {};
135
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100136TEST_P(VirtualCameraDeviceCharacterisicsTest,
137 cameraCharacteristicsForInputFormat) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100138 const VirtualCameraConfigTestParam& param = GetParam();
139 std::shared_ptr<VirtualCameraDevice> camera =
Biswarup Pal6152a302023-12-19 12:44:09 +0000140 ndk::SharedRefBase::make<VirtualCameraDevice>(kCameraId,
141 param.inputConfig);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100142
143 CameraMetadata metadata;
144 ASSERT_TRUE(camera->getCameraCharacteristics(&metadata).isOk());
145 EXPECT_THAT(getAvailableStreamConfigurations(metadata),
146 UnorderedElementsAreArray(param.expectedAvailableStreamConfigs));
147
148 // Configuration needs to succeed for every available stream configuration
149 for (const AvailableStreamConfiguration& config :
150 param.expectedAvailableStreamConfigs) {
151 StreamConfiguration configuration{
152 .streams = std::vector<Stream>{Stream{
153 .streamType = StreamType::OUTPUT,
154 .width = config.width,
155 .height = config.height,
156 .format = static_cast<PixelFormat>(config.pixelFormat),
157 }}};
158 bool aidl_ret;
159 ASSERT_TRUE(
160 camera->isStreamCombinationSupported(configuration, &aidl_ret).isOk());
161 EXPECT_TRUE(aidl_ret);
162 }
163}
164
165INSTANTIATE_TEST_SUITE_P(
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100166 cameraCharacteristicsForInputFormat, VirtualCameraDeviceCharacterisicsTest,
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100167 testing::Values(
168 VirtualCameraConfigTestParam{
Biswarup Pal6152a302023-12-19 12:44:09 +0000169 .inputConfig =
170 VirtualCameraConfiguration{
171 .supportedStreamConfigs = {SupportedStreamConfiguration{
172 .width = kVgaWidth,
173 .height = kVgaHeight,
174 .pixelFormat = Format::YUV_420_888,
175 .maxFps = kMaxFps}},
176 .virtualCameraCallback = nullptr,
Biswarup Pal112458f2023-12-28 19:50:17 +0000177 .sensorOrientation = SensorOrientation::ORIENTATION_0,
178 .lensFacing = LensFacing::FRONT},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100179 .expectedAvailableStreamConfigs =
180 {AvailableStreamConfiguration{
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100181 .width = kQvgaWidth,
182 .height = kQvgaHeight,
183 .pixelFormat =
184 ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
185 AvailableStreamConfiguration{
186 .width = kQvgaWidth,
187 .height = kQvgaHeight,
188 .pixelFormat =
189 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
190 AvailableStreamConfiguration{
191 .width = kQvgaWidth,
192 .height = kQvgaHeight,
193 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100194 AvailableStreamConfiguration{
195 .width = kVgaWidth,
196 .height = kVgaHeight,
197 .pixelFormat =
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100198 ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100199 AvailableStreamConfiguration{
200 .width = kVgaWidth,
201 .height = kVgaHeight,
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100202 .pixelFormat =
203 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
204 AvailableStreamConfiguration{
205 .width = kVgaWidth,
206 .height = kVgaHeight,
207 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB}}},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100208 VirtualCameraConfigTestParam{
Biswarup Pal6152a302023-12-19 12:44:09 +0000209 .inputConfig =
210 VirtualCameraConfiguration{
211 .supportedStreamConfigs =
212 {SupportedStreamConfiguration{
213 .width = kVgaWidth,
214 .height = kVgaHeight,
215 .pixelFormat = Format::YUV_420_888,
216 .maxFps = kMaxFps},
217 SupportedStreamConfiguration{
218 .width = kHdWidth,
219 .height = kHdHeight,
220 .pixelFormat = Format::YUV_420_888,
221 .maxFps = kMaxFps}},
222 .virtualCameraCallback = nullptr,
Biswarup Pal112458f2023-12-28 19:50:17 +0000223 .sensorOrientation = SensorOrientation::ORIENTATION_0,
224 .lensFacing = LensFacing::BACK},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100225 .expectedAvailableStreamConfigs = {
226 AvailableStreamConfiguration{
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100227 .width = kQvgaWidth,
228 .height = kQvgaHeight,
229 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
230 AvailableStreamConfiguration{
231 .width = kQvgaWidth,
232 .height = kQvgaHeight,
233 .pixelFormat =
234 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
235 AvailableStreamConfiguration{
236 .width = kQvgaWidth,
237 .height = kQvgaHeight,
238 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
239 AvailableStreamConfiguration{
240 .width = 640,
241 .height = 360,
242 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
243 AvailableStreamConfiguration{
244 .width = 640,
245 .height = 360,
246 .pixelFormat =
247 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
248 AvailableStreamConfiguration{
249 .width = 640,
250 .height = 360,
251 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
252 AvailableStreamConfiguration{
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100253 .width = kVgaWidth,
254 .height = kVgaHeight,
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100255 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100256 AvailableStreamConfiguration{
257 .width = kVgaWidth,
258 .height = kVgaHeight,
259 .pixelFormat =
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100260 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100261 AvailableStreamConfiguration{
262 .width = kVgaWidth,
263 .height = kVgaHeight,
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100264 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
265 AvailableStreamConfiguration{
266 .width = 1024,
267 .height = 576,
268 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
269 AvailableStreamConfiguration{
270 .width = 1024,
271 .height = 576,
272 .pixelFormat =
273 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
274 AvailableStreamConfiguration{
275 .width = 1024,
276 .height = 576,
277 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100278 AvailableStreamConfiguration{
279 .width = kHdWidth,
280 .height = kHdHeight,
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100281 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100282 AvailableStreamConfiguration{
283 .width = kHdWidth,
284 .height = kHdHeight,
285 .pixelFormat =
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100286 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED},
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100287 AvailableStreamConfiguration{
288 .width = kHdWidth,
289 .height = kHdHeight,
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100290 .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB}}}));
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100291
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100292class VirtualCameraDeviceTest : public ::testing::Test {
293 public:
294 void SetUp() override {
295 mCamera = ndk::SharedRefBase::make<VirtualCameraDevice>(
296 kCameraId, 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 }
306
307 protected:
308 std::shared_ptr<VirtualCameraDevice> mCamera;
309};
310
311TEST_F(VirtualCameraDeviceTest, configureMaximalNumberOfNonStallStreamsSuceeds) {
312 StreamConfiguration config;
313 std::fill_n(std::back_insert_iterator(config.streams),
314 VirtualCameraDevice::kMaxNumberOfProcessedStreams,
315 kVgaYUV420Stream);
316
317 bool aidl_ret;
318 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
319 EXPECT_TRUE(aidl_ret);
320}
321
322TEST_F(VirtualCameraDeviceTest, configureTooManyNonStallStreamsFails) {
323 StreamConfiguration config;
324 std::fill_n(std::back_insert_iterator(config.streams),
325 VirtualCameraDevice::kMaxNumberOfProcessedStreams + 1,
326 kVgaYUV420Stream);
327
328 bool aidl_ret;
329 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
330 EXPECT_FALSE(aidl_ret);
331}
332
333TEST_F(VirtualCameraDeviceTest, configureMaximalNumberOfStallStreamsSuceeds) {
334 StreamConfiguration config;
335 std::fill_n(std::back_insert_iterator(config.streams),
336 VirtualCameraDevice::kMaxNumberOfStallStreams, kVgaJpegStream);
337
338 bool aidl_ret;
339 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
340 EXPECT_TRUE(aidl_ret);
341}
342
343TEST_F(VirtualCameraDeviceTest, configureTooManyStallStreamsFails) {
344 StreamConfiguration config;
345 std::fill_n(std::back_insert_iterator(config.streams),
346 VirtualCameraDevice::kMaxNumberOfStallStreams + 1, kVgaJpegStream);
347
348 bool aidl_ret;
349 ASSERT_TRUE(mCamera->isStreamCombinationSupported(config, &aidl_ret).isOk());
350 EXPECT_FALSE(aidl_ret);
351}
352
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100353TEST_F(VirtualCameraDeviceTest, thumbnailSizeWithCompatibleAspectRatio) {
354 CameraMetadata metadata;
355 ASSERT_TRUE(mCamera->getCameraCharacteristics(&metadata).isOk());
356
357 // Camera is configured with VGA input, we expect 240 x 180 thumbnail size in
358 // characteristics, since it has same aspect ratio.
359 EXPECT_THAT(getJpegAvailableThumbnailSizes(metadata),
360 ElementsAre(Resolution(0, 0), Resolution(240, 180)));
361}
362
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100363} // namespace
364} // namespace virtualcamera
365} // namespace companion
366} // namespace android