xref: /aosp_15_r20/frameworks/av/services/camera/libcameraservice/tests/DepthProcessorTest.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2019 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 #define LOG_NDEBUG 0
18 #define LOG_TAG "DepthProcessorTest"
19 
20 #include <array>
21 #include <random>
22 
23 #include <gtest/gtest.h>
24 
25 #include "../common/DepthPhotoProcessor.h"
26 #include "../utils/ExifUtils.h"
27 #include "NV12Compressor.h"
28 
29 using namespace android;
30 using namespace android::camera3;
31 
32 static const size_t kTestBufferWidth = 640;
33 static const size_t kTestBufferHeight = 480;
34 static const size_t kTestBufferNV12Size ((((kTestBufferWidth) * (kTestBufferHeight)) * 3) / 2);
35 static const size_t kTestBufferDepthSize (kTestBufferWidth * kTestBufferHeight);
36 static const size_t kSeed = 1234;
37 
generateColorJpegBuffer(int jpegQuality,ExifOrientation orientationValue,bool includeExif,bool switchDimensions,std::vector<uint8_t> * colorJpegBuffer)38 void generateColorJpegBuffer(int jpegQuality, ExifOrientation orientationValue, bool includeExif,
39         bool switchDimensions, std::vector<uint8_t> *colorJpegBuffer /*out*/) {
40     ASSERT_NE(colorJpegBuffer, nullptr);
41 
42     std::array<uint8_t, kTestBufferNV12Size> colorSourceBuffer;
43     std::default_random_engine gen(kSeed);
44     std::uniform_int_distribution<int> uniDist(0, UINT8_MAX - 1);
45     for (size_t i = 0; i < colorSourceBuffer.size(); i++) {
46         colorSourceBuffer[i] = uniDist(gen);
47     }
48 
49     size_t width = kTestBufferWidth;
50     size_t height = kTestBufferHeight;
51     if (switchDimensions) {
52         width = kTestBufferHeight;
53         height = kTestBufferWidth;
54     }
55 
56     NV12Compressor jpegCompressor;
57     if (includeExif) {
58         ASSERT_TRUE(jpegCompressor.compressWithExifOrientation(
59                 reinterpret_cast<const unsigned char*> (colorSourceBuffer.data()), width, height,
60                 jpegQuality, orientationValue));
61     } else {
62         ASSERT_TRUE(jpegCompressor.compress(
63                 reinterpret_cast<const unsigned char*> (colorSourceBuffer.data()), width, height,
64                 jpegQuality));
65     }
66 
67     *colorJpegBuffer = std::move(jpegCompressor.getCompressedData());
68     ASSERT_FALSE(colorJpegBuffer->empty());
69 }
70 
generateDepth16Buffer(std::array<uint16_t,kTestBufferDepthSize> * depth16Buffer)71 void generateDepth16Buffer(std::array<uint16_t, kTestBufferDepthSize> *depth16Buffer /*out*/) {
72     ASSERT_NE(depth16Buffer, nullptr);
73     std::default_random_engine gen(kSeed+1);
74     std::uniform_int_distribution<int> uniDist(0, UINT16_MAX - 1);
75     for (size_t i = 0; i < depth16Buffer->size(); i++) {
76         (*depth16Buffer)[i] = uniDist(gen);
77     }
78 }
79 
TEST(DepthProcessorTest,BadInput)80 TEST(DepthProcessorTest, BadInput) {
81     static const size_t badInputBufferWidth = 17;
82     static const size_t badInputBufferHeight = 3;
83     static const size_t badInputJpegSize = 63;
84     static const size_t badInputBufferDepthSize = (badInputBufferWidth * badInputBufferHeight);
85     int jpegQuality = 95;
86 
87     DepthPhotoInputFrame inputFrame;
88     std::vector<uint8_t> colorJpegBuffer(badInputJpegSize);
89     inputFrame.mMainJpegSize = colorJpegBuffer.size();
90     // Worst case both depth and confidence maps have the same size as the main color image.
91     inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * 3;
92 
93     std::array<uint16_t, badInputBufferDepthSize> depth16Buffer;
94 
95     std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
96     size_t actualDepthPhotoSize = 0;
97 
98     inputFrame.mMainJpegWidth = badInputBufferWidth;
99     inputFrame.mMainJpegHeight = badInputBufferHeight;
100     inputFrame.mJpegQuality = jpegQuality;
101     ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
102                 &actualDepthPhotoSize), 0);
103 
104     inputFrame.mMainJpegBuffer = reinterpret_cast<const char*> (colorJpegBuffer.data());
105     ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
106                 &actualDepthPhotoSize), 0);
107 
108     inputFrame.mDepthMapBuffer = depth16Buffer.data();
109     inputFrame.mDepthMapWidth = inputFrame.mDepthMapStride = kTestBufferWidth;
110     inputFrame.mDepthMapHeight = kTestBufferHeight;
111     ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), nullptr,
112                 &actualDepthPhotoSize), 0);
113 
114     ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
115                 nullptr), 0);
116 
117     ASSERT_NE(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
118                 &actualDepthPhotoSize), 0);
119 }
120 
TEST(DepthProcessorTest,BasicDepthPhotoValidation)121 TEST(DepthProcessorTest, BasicDepthPhotoValidation) {
122     int jpegQuality = 95;
123 
124     std::vector<uint8_t> colorJpegBuffer;
125     generateColorJpegBuffer(jpegQuality, ExifOrientation::ORIENTATION_UNDEFINED,
126             /*includeExif*/ false, /*switchDimensions*/ false, &colorJpegBuffer);
127 
128     std::array<uint16_t, kTestBufferDepthSize> depth16Buffer;
129     generateDepth16Buffer(&depth16Buffer);
130 
131     DepthPhotoInputFrame inputFrame;
132     inputFrame.mMainJpegBuffer = reinterpret_cast<const char*> (colorJpegBuffer.data());
133     inputFrame.mMainJpegSize = colorJpegBuffer.size();
134     // Worst case both depth and confidence maps have the same size as the main color image.
135     inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * 3;
136     inputFrame.mMainJpegWidth = kTestBufferWidth;
137     inputFrame.mMainJpegHeight = kTestBufferHeight;
138     inputFrame.mJpegQuality = jpegQuality;
139     inputFrame.mDepthMapBuffer = depth16Buffer.data();
140     inputFrame.mDepthMapWidth = inputFrame.mDepthMapStride = kTestBufferWidth;
141     inputFrame.mDepthMapHeight = kTestBufferHeight;
142 
143     std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
144     size_t actualDepthPhotoSize = 0;
145     ASSERT_EQ(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
146                 &actualDepthPhotoSize), 0);
147     ASSERT_TRUE((actualDepthPhotoSize > 0) && (depthPhotoBuffer.size() >= actualDepthPhotoSize));
148 
149     // The final depth photo must consist of three jpeg images:
150     //  - the main color image
151     //  - the depth map image
152     //  - the confidence map image
153     size_t mainJpegSize = 0;
154     ASSERT_EQ(NV12Compressor::findJpegSize(depthPhotoBuffer.data(), actualDepthPhotoSize,
155                 &mainJpegSize), OK);
156     ASSERT_TRUE((mainJpegSize > 0) && (mainJpegSize < actualDepthPhotoSize));
157     size_t depthMapSize = 0;
158     ASSERT_EQ(NV12Compressor::findJpegSize(depthPhotoBuffer.data() + mainJpegSize,
159                 actualDepthPhotoSize - mainJpegSize, &depthMapSize), OK);
160     ASSERT_TRUE((depthMapSize > 0) && (depthMapSize < (actualDepthPhotoSize - mainJpegSize)));
161 }
162 
TEST(DepthProcessorTest,TestDepthPhotoExifOrientation)163 TEST(DepthProcessorTest, TestDepthPhotoExifOrientation) {
164     int jpegQuality = 95;
165 
166     ExifOrientation exifOrientations[] = { ExifOrientation::ORIENTATION_UNDEFINED,
167             ExifOrientation::ORIENTATION_0_DEGREES, ExifOrientation::ORIENTATION_90_DEGREES,
168             ExifOrientation::ORIENTATION_180_DEGREES, ExifOrientation::ORIENTATION_270_DEGREES };
169     for (auto exifOrientation : exifOrientations) {
170         std::vector<uint8_t> colorJpegBuffer;
171         generateColorJpegBuffer(jpegQuality, exifOrientation, /*includeExif*/ true,
172                 /*switchDimensions*/ false, &colorJpegBuffer);
173         if (exifOrientation != ExifOrientation::ORIENTATION_UNDEFINED) {
174             auto jpegExifOrientation = ExifOrientation::ORIENTATION_UNDEFINED;
175             ASSERT_EQ(NV12Compressor::getExifOrientation(colorJpegBuffer.data(),
176                     colorJpegBuffer.size(), &jpegExifOrientation), OK);
177             ASSERT_EQ(exifOrientation, jpegExifOrientation);
178         }
179 
180         std::array<uint16_t, kTestBufferDepthSize> depth16Buffer;
181         generateDepth16Buffer(&depth16Buffer);
182 
183         DepthPhotoInputFrame inputFrame;
184         inputFrame.mMainJpegBuffer = reinterpret_cast<const char*> (colorJpegBuffer.data());
185         inputFrame.mMainJpegSize = colorJpegBuffer.size();
186         // Worst case both depth and confidence maps have the same size as the main color image.
187         inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * 3;
188         inputFrame.mMainJpegWidth = kTestBufferWidth;
189         inputFrame.mMainJpegHeight = kTestBufferHeight;
190         inputFrame.mJpegQuality = jpegQuality;
191         inputFrame.mDepthMapBuffer = depth16Buffer.data();
192         inputFrame.mDepthMapWidth = inputFrame.mDepthMapStride = kTestBufferWidth;
193         inputFrame.mDepthMapHeight = kTestBufferHeight;
194 
195         std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
196         size_t actualDepthPhotoSize = 0;
197         ASSERT_EQ(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(),
198                     depthPhotoBuffer.data(), &actualDepthPhotoSize), 0);
199         ASSERT_TRUE((actualDepthPhotoSize > 0) &&
200                 (depthPhotoBuffer.size() >= actualDepthPhotoSize));
201 
202         size_t mainJpegSize = 0;
203         ASSERT_EQ(NV12Compressor::findJpegSize(depthPhotoBuffer.data(), actualDepthPhotoSize,
204                 &mainJpegSize), OK);
205         ASSERT_TRUE((mainJpegSize > 0) && (mainJpegSize < actualDepthPhotoSize));
206         size_t depthMapSize = 0;
207         ASSERT_EQ(NV12Compressor::findJpegSize(depthPhotoBuffer.data() + mainJpegSize,
208                 actualDepthPhotoSize - mainJpegSize, &depthMapSize), OK);
209         ASSERT_TRUE((depthMapSize > 0) && (depthMapSize < (actualDepthPhotoSize - mainJpegSize)));
210         size_t confidenceMapSize = actualDepthPhotoSize - (mainJpegSize + depthMapSize);
211 
212         //Depth and confidence images must have the same EXIF orientation as the source
213         auto depthJpegExifOrientation = ExifOrientation::ORIENTATION_UNDEFINED;
214         ASSERT_EQ(NV12Compressor::getExifOrientation(depthPhotoBuffer.data() + mainJpegSize,
215                 depthMapSize, &depthJpegExifOrientation), OK);
216         if (exifOrientation == ORIENTATION_UNDEFINED) {
217             // In case of undefined or missing EXIF orientation, always expect 0 degrees in the
218             // depth map.
219             ASSERT_EQ(depthJpegExifOrientation, ExifOrientation::ORIENTATION_0_DEGREES);
220         } else {
221             ASSERT_EQ(depthJpegExifOrientation, exifOrientation);
222         }
223 
224         auto confidenceJpegExifOrientation = ExifOrientation::ORIENTATION_UNDEFINED;
225         ASSERT_EQ(NV12Compressor::getExifOrientation(
226                 depthPhotoBuffer.data() + mainJpegSize + depthMapSize,
227                 confidenceMapSize, &confidenceJpegExifOrientation), OK);
228         if (exifOrientation == ORIENTATION_UNDEFINED) {
229             // In case of undefined or missing EXIF orientation, always expect 0 degrees in the
230             // confidence map.
231             ASSERT_EQ(confidenceJpegExifOrientation, ExifOrientation::ORIENTATION_0_DEGREES);
232         } else {
233             ASSERT_EQ(confidenceJpegExifOrientation, exifOrientation);
234         }
235     }
236 }
237 
TEST(DepthProcessorTest,TestDephtPhotoPhysicalRotation)238 TEST(DepthProcessorTest, TestDephtPhotoPhysicalRotation) {
239     int jpegQuality = 95;
240 
241     // In case of physical rotation, the EXIF orientation must always be 0.
242     auto exifOrientation = ExifOrientation::ORIENTATION_0_DEGREES;
243     DepthPhotoOrientation depthOrientations[] = {
244             DepthPhotoOrientation::DEPTH_ORIENTATION_0_DEGREES,
245             DepthPhotoOrientation::DEPTH_ORIENTATION_90_DEGREES,
246             DepthPhotoOrientation::DEPTH_ORIENTATION_180_DEGREES,
247             DepthPhotoOrientation::DEPTH_ORIENTATION_270_DEGREES };
248     for (auto depthOrientation : depthOrientations) {
249         std::vector<uint8_t> colorJpegBuffer;
250         bool switchDimensions = false;
251         size_t expectedWidth = kTestBufferWidth;
252         size_t expectedHeight = kTestBufferHeight;
253         if ((depthOrientation == DepthPhotoOrientation::DEPTH_ORIENTATION_90_DEGREES) ||
254                 (depthOrientation == DepthPhotoOrientation::DEPTH_ORIENTATION_270_DEGREES)) {
255             switchDimensions = true;
256             expectedWidth = kTestBufferHeight;
257             expectedHeight = kTestBufferWidth;
258         }
259         generateColorJpegBuffer(jpegQuality, exifOrientation, /*includeExif*/ true,
260                 switchDimensions, &colorJpegBuffer);
261         auto jpegExifOrientation = ExifOrientation::ORIENTATION_UNDEFINED;
262         ASSERT_EQ(NV12Compressor::getExifOrientation(colorJpegBuffer.data(), colorJpegBuffer.size(),
263                 &jpegExifOrientation), OK);
264         ASSERT_EQ(exifOrientation, jpegExifOrientation);
265 
266         std::array<uint16_t, kTestBufferDepthSize> depth16Buffer;
267         generateDepth16Buffer(&depth16Buffer);
268 
269         DepthPhotoInputFrame inputFrame;
270         inputFrame.mMainJpegBuffer = reinterpret_cast<const char*> (colorJpegBuffer.data());
271         inputFrame.mMainJpegSize = colorJpegBuffer.size();
272         // Worst case both depth and confidence maps have the same size as the main color image.
273         inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * 3;
274         inputFrame.mMainJpegWidth = kTestBufferWidth;
275         inputFrame.mMainJpegHeight = kTestBufferHeight;
276         inputFrame.mJpegQuality = jpegQuality;
277         inputFrame.mDepthMapBuffer = depth16Buffer.data();
278         inputFrame.mDepthMapWidth = inputFrame.mDepthMapStride = kTestBufferWidth;
279         inputFrame.mDepthMapHeight = kTestBufferHeight;
280         inputFrame.mOrientation = depthOrientation;
281 
282         std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
283         size_t actualDepthPhotoSize = 0;
284         ASSERT_EQ(processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(),
285                     depthPhotoBuffer.data(), &actualDepthPhotoSize), 0);
286         ASSERT_TRUE((actualDepthPhotoSize > 0) &&
287                 (depthPhotoBuffer.size() >= actualDepthPhotoSize));
288 
289         size_t mainJpegSize = 0;
290         ASSERT_EQ(NV12Compressor::findJpegSize(depthPhotoBuffer.data(), actualDepthPhotoSize,
291                 &mainJpegSize), OK);
292         ASSERT_TRUE((mainJpegSize > 0) && (mainJpegSize < actualDepthPhotoSize));
293         size_t depthMapSize = 0;
294         ASSERT_EQ(NV12Compressor::findJpegSize(depthPhotoBuffer.data() + mainJpegSize,
295                 actualDepthPhotoSize - mainJpegSize, &depthMapSize), OK);
296         ASSERT_TRUE((depthMapSize > 0) && (depthMapSize < (actualDepthPhotoSize - mainJpegSize)));
297         size_t confidenceMapSize = actualDepthPhotoSize - (mainJpegSize + depthMapSize);
298 
299         //Depth and confidence images must have the same EXIF orientation as the source
300         auto depthJpegExifOrientation = ExifOrientation::ORIENTATION_UNDEFINED;
301         ASSERT_EQ(NV12Compressor::getExifOrientation(depthPhotoBuffer.data() + mainJpegSize,
302                 depthMapSize, &depthJpegExifOrientation), OK);
303         ASSERT_EQ(depthJpegExifOrientation, exifOrientation);
304         size_t depthMapWidth, depthMapHeight;
305         ASSERT_EQ(NV12Compressor::getJpegImageDimensions(depthPhotoBuffer.data() + mainJpegSize,
306                 depthMapSize, &depthMapWidth, &depthMapHeight), OK);
307         ASSERT_EQ(depthMapWidth, expectedWidth);
308         ASSERT_EQ(depthMapHeight, expectedHeight);
309 
310         auto confidenceJpegExifOrientation = ExifOrientation::ORIENTATION_UNDEFINED;
311         ASSERT_EQ(NV12Compressor::getExifOrientation(
312                 depthPhotoBuffer.data() + mainJpegSize + depthMapSize, confidenceMapSize,
313                 &confidenceJpegExifOrientation), OK);
314         ASSERT_EQ(confidenceJpegExifOrientation, exifOrientation);
315         size_t confidenceMapWidth, confidenceMapHeight;
316         ASSERT_EQ(NV12Compressor::getJpegImageDimensions(
317                 depthPhotoBuffer.data() + mainJpegSize + depthMapSize, confidenceMapSize,
318                 &confidenceMapWidth, &confidenceMapHeight), OK);
319         ASSERT_EQ(confidenceMapWidth, expectedWidth);
320         ASSERT_EQ(confidenceMapHeight, expectedHeight);
321     }
322 }
323