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