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