• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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_TAG "AImageReaderCts"
18 //#define LOG_NDEBUG 0
19 
20 #include <jni.h>
21 #include <stdint.h>
22 #include <unistd.h>
23 
24 #include <algorithm>
25 #include <mutex>
26 #include <string>
27 #include <vector>
28 
29 #include <android/log.h>
30 #include <android/native_window_jni.h>
31 #include <camera/NdkCameraError.h>
32 #include <camera/NdkCameraManager.h>
33 #include <camera/NdkCameraDevice.h>
34 #include <camera/NdkCameraCaptureSession.h>
35 #include <media/NdkImage.h>
36 #include <media/NdkImageReader.h>
37 
38 //#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
39 //#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
40 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
41 #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
42 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
43 
44 namespace {
45 
46 static constexpr int kDummyFenceFd = -1;
47 static constexpr int kCaptureWaitUs = 100 * 1000;
48 static constexpr int kCaptureWaitRetry = 10;
49 static constexpr int kTestImageWidth = 640;
50 static constexpr int kTestImageHeight = 480;
51 static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888;
52 
53 struct FormatUsageCombination {
54     uint64_t format;
55     uint64_t usage;
56 };
57 
58 static constexpr FormatUsageCombination supportedFormatUsage[] = {
59     {AIMAGE_FORMAT_YUV_420_888, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY},
60     {AIMAGE_FORMAT_YUV_420_888, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN},
61     {AIMAGE_FORMAT_JPEG, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY},
62     {AIMAGE_FORMAT_JPEG, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN},
63     {AIMAGE_FORMAT_RGBA_8888, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY},
64     {AIMAGE_FORMAT_RGBA_8888, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN},
65     {AIMAGE_FORMAT_RGBA_8888, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE},
66     {AIMAGE_FORMAT_RGBA_8888, AHARDWAREBUFFER_USAGE_VIDEO_ENCODE},
67     {AIMAGE_FORMAT_Y8, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN},
68 };
69 
70 class CameraHelper {
71    public:
CameraHelper(ANativeWindow * imgReaderAnw)72     CameraHelper(ANativeWindow* imgReaderAnw) : mImgReaderAnw(imgReaderAnw) {}
~CameraHelper()73     ~CameraHelper() { closeCamera(); }
74 
initCamera()75     int initCamera() {
76         if (mImgReaderAnw == nullptr) {
77             ALOGE("Cannot initialize camera before image reader get initialized.");
78             return -1;
79         }
80         int ret;
81 
82         mCameraManager = ACameraManager_create();
83         if (mCameraManager == nullptr) {
84             ALOGE("Failed to create ACameraManager.");
85             return -1;
86         }
87 
88         ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
89         if (ret != AMEDIA_OK) {
90             ALOGE("Failed to get cameraIdList: ret=%d", ret);
91             return ret;
92         }
93         if (mCameraIdList->numCameras < 1) {
94             ALOGW("Device has no camera on board.");
95             return 0;
96         }
97 
98         // We always use the first camera.
99         mCameraId = mCameraIdList->cameraIds[0];
100         if (mCameraId == nullptr) {
101             ALOGE("Failed to get cameraId.");
102             return -1;
103         }
104 
105         ret = ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice);
106         if (ret != AMEDIA_OK || mDevice == nullptr) {
107             ALOGE("Failed to open camera, ret=%d, mDevice=%p.", ret, mDevice);
108             return -1;
109         }
110 
111         ret = ACameraManager_getCameraCharacteristics(mCameraManager, mCameraId, &mCameraMetadata);
112         if (ret != ACAMERA_OK || mCameraMetadata == nullptr) {
113             ALOGE("Get camera %s characteristics failure. ret %d, metadata %p", mCameraId, ret,
114                   mCameraMetadata);
115             return -1;
116         }
117 
118         if (!isCapabilitySupported(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)) {
119             ALOGW("Camera does not support BACKWARD_COMPATIBLE.");
120             return 0;
121         }
122 
123         // Create capture session
124         ret = ACaptureSessionOutputContainer_create(&mOutputs);
125         if (ret != AMEDIA_OK) {
126             ALOGE("ACaptureSessionOutputContainer_create failed, ret=%d", ret);
127             return ret;
128         }
129         ret = ACaptureSessionOutput_create(mImgReaderAnw, &mImgReaderOutput);
130         if (ret != AMEDIA_OK) {
131             ALOGE("ACaptureSessionOutput_create failed, ret=%d", ret);
132             return ret;
133         }
134         ret = ACaptureSessionOutputContainer_add(mOutputs, mImgReaderOutput);
135         if (ret != AMEDIA_OK) {
136             ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
137             return ret;
138         }
139         ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
140         if (ret != AMEDIA_OK) {
141             ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret);
142             return ret;
143         }
144 
145         // Create capture request
146         ret = ACameraDevice_createCaptureRequest(mDevice, TEMPLATE_STILL_CAPTURE, &mStillRequest);
147         if (ret != AMEDIA_OK) {
148             ALOGE("ACameraDevice_createCaptureRequest failed, ret=%d", ret);
149             return ret;
150         }
151         ret = ACameraOutputTarget_create(mImgReaderAnw, &mReqImgReaderOutput);
152         if (ret != AMEDIA_OK) {
153             ALOGE("ACameraOutputTarget_create failed, ret=%d", ret);
154             return ret;
155         }
156         ret = ACaptureRequest_addTarget(mStillRequest, mReqImgReaderOutput);
157         if (ret != AMEDIA_OK) {
158             ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret);
159             return ret;
160         }
161 
162         mIsCameraReady = true;
163         return 0;
164     }
165 
isCapabilitySupported(acamera_metadata_enum_android_request_available_capabilities_t cap)166     bool isCapabilitySupported(acamera_metadata_enum_android_request_available_capabilities_t cap) {
167         ACameraMetadata_const_entry entry;
168         ACameraMetadata_getConstEntry(
169                 mCameraMetadata, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
170         for (uint32_t i = 0; i < entry.count; i++) {
171             if (entry.data.u8[i] == cap) {
172                 return true;
173             }
174         }
175         return false;
176     }
177 
isCameraReady()178     bool isCameraReady() { return mIsCameraReady; }
179 
closeCamera()180     void closeCamera() {
181         // Destroy capture request
182         if (mReqImgReaderOutput) {
183             ACameraOutputTarget_free(mReqImgReaderOutput);
184             mReqImgReaderOutput = nullptr;
185         }
186         if (mStillRequest) {
187             ACaptureRequest_free(mStillRequest);
188             mStillRequest = nullptr;
189         }
190         // Destroy capture session
191         if (mSession != nullptr) {
192             ACameraCaptureSession_close(mSession);
193             mSession = nullptr;
194         }
195         if (mImgReaderOutput) {
196             ACaptureSessionOutput_free(mImgReaderOutput);
197             mImgReaderOutput = nullptr;
198         }
199         if (mOutputs) {
200             ACaptureSessionOutputContainer_free(mOutputs);
201             mOutputs = nullptr;
202         }
203         // Destroy camera device
204         if (mDevice) {
205             ACameraDevice_close(mDevice);
206             mDevice = nullptr;
207         }
208         if (mCameraMetadata) {
209           ACameraMetadata_free(mCameraMetadata);
210           mCameraMetadata = nullptr;
211         }
212         // Destroy camera manager
213         if (mCameraIdList) {
214             ACameraManager_deleteCameraIdList(mCameraIdList);
215             mCameraIdList = nullptr;
216         }
217         if (mCameraManager) {
218             ACameraManager_delete(mCameraManager);
219             mCameraManager = nullptr;
220         }
221         mIsCameraReady = false;
222     }
223 
takePicture()224     int takePicture() {
225         int seqId;
226         return ACameraCaptureSession_capture(mSession, nullptr, 1, &mStillRequest, &seqId);
227     }
228 
onDeviceDisconnected(void *,ACameraDevice *)229     static void onDeviceDisconnected(void* /*obj*/, ACameraDevice* /*device*/) {}
230 
onDeviceError(void *,ACameraDevice *,int)231     static void onDeviceError(void* /*obj*/, ACameraDevice* /*device*/, int /*errorCode*/) {}
232 
onSessionClosed(void *,ACameraCaptureSession *)233     static void onSessionClosed(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
234 
onSessionReady(void *,ACameraCaptureSession *)235     static void onSessionReady(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
236 
onSessionActive(void *,ACameraCaptureSession *)237     static void onSessionActive(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
238 
239    private:
240     ACameraDevice_StateCallbacks mDeviceCb{this, onDeviceDisconnected,
241                                            onDeviceError};
242     ACameraCaptureSession_stateCallbacks mSessionCb{
243         this, onSessionClosed, onSessionReady, onSessionActive};
244 
245     ANativeWindow* mImgReaderAnw = nullptr;  // not owned by us.
246 
247     // Camera manager
248     ACameraManager* mCameraManager = nullptr;
249     ACameraIdList* mCameraIdList = nullptr;
250     // Camera device
251     ACameraMetadata* mCameraMetadata = nullptr;
252     ACameraDevice* mDevice = nullptr;
253     // Capture session
254     ACaptureSessionOutputContainer* mOutputs = nullptr;
255     ACaptureSessionOutput* mImgReaderOutput = nullptr;
256     ACameraCaptureSession* mSession = nullptr;
257     // Capture request
258     ACaptureRequest* mStillRequest = nullptr;
259     ACameraOutputTarget* mReqImgReaderOutput = nullptr;
260 
261     bool mIsCameraReady = false;
262     const char* mCameraId;
263 };
264 
265 class ImageReaderTestCase {
266    public:
ImageReaderTestCase(int32_t width,int32_t height,int32_t format,uint64_t usage,int32_t maxImages,bool async)267     ImageReaderTestCase(int32_t width,
268                         int32_t height,
269                         int32_t format,
270                         uint64_t usage,
271                         int32_t maxImages,
272                         bool async)
273         : mWidth(width),
274           mHeight(height),
275           mFormat(format),
276           mUsage(usage),
277           mMaxImages(maxImages),
278           mAsync(async) {}
279 
~ImageReaderTestCase()280     ~ImageReaderTestCase() {
281         if (mImgReaderAnw) {
282             AImageReader_delete(mImgReader);
283             // No need to call ANativeWindow_release on imageReaderAnw
284         }
285     }
286 
initImageReader()287     int initImageReader() {
288         if (mImgReader != nullptr || mImgReaderAnw != nullptr) {
289             ALOGE("Cannot re-initalize image reader, mImgReader=%p, mImgReaderAnw=%p", mImgReader,
290                   mImgReaderAnw);
291             return -1;
292         }
293 
294         media_status_t ret = AImageReader_newWithUsage(
295                 mWidth, mHeight, mFormat, mUsage, mMaxImages, &mImgReader);
296         if (ret != AMEDIA_OK || mImgReader == nullptr) {
297             ALOGE("Failed to create new AImageReader, ret=%d, mImgReader=%p", ret, mImgReader);
298             return -1;
299         }
300 
301         ret = AImageReader_setImageListener(mImgReader, &mReaderAvailableCb);
302         if (ret != AMEDIA_OK) {
303             ALOGE("Failed to set image available listener, ret=%d.", ret);
304             return ret;
305         }
306 
307         ret = AImageReader_setBufferRemovedListener(mImgReader, &mReaderDetachedCb);
308         if (ret != AMEDIA_OK) {
309             ALOGE("Failed to set buffer detaching listener, ret=%d.", ret);
310             return ret;
311         }
312 
313         ret = AImageReader_getWindow(mImgReader, &mImgReaderAnw);
314         if (ret != AMEDIA_OK || mImgReaderAnw == nullptr) {
315             ALOGE("Failed to get ANativeWindow from AImageReader, ret=%d, mImgReaderAnw=%p.", ret,
316                   mImgReaderAnw);
317             return -1;
318         }
319 
320         return 0;
321     }
322 
getNativeWindow()323     ANativeWindow* getNativeWindow() { return mImgReaderAnw; }
324 
getAcquiredImageCount()325     int getAcquiredImageCount() {
326         std::lock_guard<std::mutex> lock(mMutex);
327         return mAcquiredImageCount;
328     }
329 
HandleImageAvailable(AImageReader * reader)330     void HandleImageAvailable(AImageReader* reader) {
331         std::lock_guard<std::mutex> lock(mMutex);
332 
333         AImage* outImage = nullptr;
334         media_status_t ret;
335 
336         // Make sure AImage will be deleted automatically when it goes out of
337         // scope.
338         auto imageDeleter = [this](AImage* img) {
339             if (mAsync) {
340                 AImage_deleteAsync(img, kDummyFenceFd);
341             } else {
342                 AImage_delete(img);
343             }
344         };
345         std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
346 
347         if (mAsync) {
348             int outFenceFd = 0;
349             // Verity that outFenceFd's value will be changed by
350             // AImageReader_acquireNextImageAsync.
351             ret = AImageReader_acquireNextImageAsync(reader, &outImage, &outFenceFd);
352             if (ret != AMEDIA_OK || outImage == nullptr || outFenceFd == 0) {
353                 ALOGE("Failed to acquire image, ret=%d, outIamge=%p, outFenceFd=%d.", ret, outImage,
354                       outFenceFd);
355                 return;
356             }
357             img.reset(outImage);
358         } else {
359             ret = AImageReader_acquireNextImage(reader, &outImage);
360             if (ret != AMEDIA_OK || outImage == nullptr) {
361                 ALOGE("Failed to acquire image, ret=%d, outIamge=%p.", ret, outImage);
362                 return;
363             }
364             img.reset(outImage);
365         }
366 
367         AHardwareBuffer* outBuffer = nullptr;
368         ret = AImage_getHardwareBuffer(img.get(), &outBuffer);
369         if (ret != AMEDIA_OK || outBuffer == nullptr) {
370             ALOGE("Faild to get hardware buffer, ret=%d, outBuffer=%p.", ret, outBuffer);
371             return;
372         }
373 
374         // No need to release AHardwareBuffer, since we don't acquire additional
375         // reference to it.
376         AHardwareBuffer_Desc outDesc;
377         AHardwareBuffer_describe(outBuffer, &outDesc);
378         int32_t imageWidth = 0;
379         int32_t imageHeight = 0;
380         int32_t bufferWidth = static_cast<int32_t>(outDesc.width);
381         int32_t bufferHeight = static_cast<int32_t>(outDesc.height);
382 
383         AImage_getWidth(outImage, &imageWidth);
384         AImage_getHeight(outImage, &imageHeight);
385         if (imageWidth != mWidth || imageHeight != mHeight) {
386             ALOGE("Mismatched output image dimension: expected=%dx%d, actual=%dx%d", mWidth,
387                   mHeight, imageWidth, imageHeight);
388             return;
389         }
390 
391         if (mFormat == AIMAGE_FORMAT_RGBA_8888 ||
392             mFormat == AIMAGE_FORMAT_RGBX_8888 ||
393             mFormat == AIMAGE_FORMAT_RGB_888 ||
394             mFormat == AIMAGE_FORMAT_RGB_565 ||
395             mFormat == AIMAGE_FORMAT_RGBA_FP16 ||
396             mFormat == AIMAGE_FORMAT_YUV_420_888 ||
397             mFormat == AIMAGE_FORMAT_Y8) {
398             // Check output buffer dimension for certain formats. Don't do this for blob based
399             // formats.
400             if (bufferWidth != mWidth || bufferHeight != mHeight) {
401                 ALOGE("Mismatched output buffer dimension: expected=%dx%d, actual=%dx%d", mWidth,
402                       mHeight, bufferWidth, bufferHeight);
403                 return;
404             }
405         }
406 
407         if ((outDesc.usage & mUsage) != mUsage) {
408             ALOGE("Mismatched output buffer usage: actual (%" PRIu64 "), expected (%" PRIu64 ")",
409                   outDesc.usage, mUsage);
410             return;
411         }
412 
413         uint8_t* data = nullptr;
414         int dataLength = 0;
415         ret = AImage_getPlaneData(img.get(), 0, &data, &dataLength);
416         if (mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) {
417             // When we have CPU_READ_OFTEN usage bits, we can lock the image.
418             if (ret != AMEDIA_OK || data == nullptr || dataLength < 0) {
419                 ALOGE("Failed to access CPU data, ret=%d, data=%p, dataLength=%d", ret, data,
420                       dataLength);
421                 return;
422             }
423         } else {
424             if (ret != AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE || data != nullptr || dataLength != 0) {
425                 ALOGE("Shouldn't be able to access CPU data, ret=%d, data=%p, dataLength=%d", ret,
426                       data, dataLength);
427                 return;
428             }
429         }
430         // Only increase mAcquiredImageCount if all checks pass.
431         mAcquiredImageCount++;
432     }
433 
onImageAvailable(void * obj,AImageReader * reader)434     static void onImageAvailable(void* obj, AImageReader* reader) {
435         ImageReaderTestCase* thiz = reinterpret_cast<ImageReaderTestCase*>(obj);
436         thiz->HandleImageAvailable(reader);
437     }
438 
439     static void
onBufferRemoved(void *,AImageReader *,AHardwareBuffer *)440     onBufferRemoved(void* /*obj*/, AImageReader* /*reader*/, AHardwareBuffer* /*buffer*/) {
441         // No-op, just to check the listener can be set properly.
442     }
443 
444    private:
445     int32_t mWidth;
446     int32_t mHeight;
447     int32_t mFormat;
448     uint64_t mUsage;
449     int32_t mMaxImages;
450     bool mAsync;
451 
452     std::mutex mMutex;
453     int mAcquiredImageCount{0};
454 
455     AImageReader* mImgReader = nullptr;
456     ANativeWindow* mImgReaderAnw = nullptr;
457 
458     AImageReader_ImageListener mReaderAvailableCb{this, onImageAvailable};
459     AImageReader_BufferRemovedListener mReaderDetachedCb{this, onBufferRemoved};
460 };
461 
takePictures(uint64_t readerUsage,int readerMaxImages,bool readerAsync,int pictureCount)462 int takePictures(uint64_t readerUsage, int readerMaxImages, bool readerAsync, int pictureCount) {
463     int ret = 0;
464 
465     ImageReaderTestCase testCase(
466             kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage, readerMaxImages,
467             readerAsync);
468     ret = testCase.initImageReader();
469     if (ret < 0) {
470         return ret;
471     }
472 
473     CameraHelper cameraHelper(testCase.getNativeWindow());
474     ret = cameraHelper.initCamera();
475     if (ret < 0) {
476         return ret;
477     }
478 
479     if (!cameraHelper.isCameraReady()) {
480         ALOGW("Camera is not ready after successful initialization. It's either due to camera on "
481               "board lacks BACKWARDS_COMPATIBLE capability or the device does not have camera on "
482               "board.");
483         return 0;
484     }
485 
486     for (int i = 0; i < pictureCount; i++) {
487         ret = cameraHelper.takePicture();
488         if (ret < 0) {
489             return ret;
490         }
491     }
492 
493     // Sleep until all capture finished
494     for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
495         usleep(kCaptureWaitUs);
496         if (testCase.getAcquiredImageCount() == pictureCount) {
497             ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
498                   pictureCount);
499             break;
500         }
501     }
502 
503     return testCase.getAcquiredImageCount() == pictureCount ? 0 : -1;
504 }
505 
506 }  // namespace
507 
508 // Test that newWithUsage can create AImageReader correctly.
Java_android_media_cts_NativeImageReaderTest_testSucceedsWithSupportedUsageFormatNative(JNIEnv *,jclass)509 extern "C" jboolean Java_android_media_cts_NativeImageReaderTest_\
510 testSucceedsWithSupportedUsageFormatNative(JNIEnv* /*env*/, jclass /*clazz*/) {
511     static constexpr int kTestImageCount = 8;
512 
513     for (auto& combination : supportedFormatUsage) {
514         AImageReader* outReader;
515         media_status_t ret = AImageReader_newWithUsage(
516                 kTestImageWidth, kTestImageHeight, combination.format, combination.usage,
517                 kTestImageCount, &outReader);
518         if (ret != AMEDIA_OK || outReader == nullptr) {
519             ALOGE("AImageReader_newWithUsage failed with format: %" PRId64 ", usage: %" PRId64 ".",
520                   combination.format, combination.usage);
521             return false;
522         }
523         AImageReader_delete(outReader);
524     }
525 
526     return true;
527 }
528 
Java_android_media_cts_NativeImageReaderTest_testTakePicturesNative(JNIEnv *,jclass)529 extern "C" jboolean Java_android_media_cts_NativeImageReaderTest_\
530 testTakePicturesNative(JNIEnv* /*env*/, jclass /*clazz*/) {
531     for (auto& readerUsage :
532          {AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN}) {
533         for (auto& readerMaxImages : {1, 4, 8}) {
534             for (auto& readerAsync : {true, false}) {
535                 for (auto& pictureCount : {1, 8, 16}) {
536                     if (takePictures(readerUsage, readerMaxImages, readerAsync, pictureCount)) {
537                         ALOGE("Test takePictures failed for test case usage=%" PRIu64 ", maxImages=%d, "
538                               "async=%d, pictureCount=%d",
539                               readerUsage, readerMaxImages, readerAsync, pictureCount);
540                         return false;
541                     }
542                 }
543             }
544         }
545     }
546     return true;
547 }
548 
Java_android_media_cts_NativeImageReaderTest_testCreateSurfaceNative(JNIEnv * env,jclass)549 extern "C" jobject Java_android_media_cts_NativeImageReaderTest_\
550 testCreateSurfaceNative(JNIEnv* env, jclass /*clazz*/) {
551     static constexpr uint64_t kTestImageUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
552     static constexpr int kTestImageCount = 8;
553 
554     ImageReaderTestCase testCase(
555             kTestImageWidth, kTestImageHeight, kTestImageFormat, kTestImageUsage, kTestImageCount,
556             false);
557     int ret = testCase.initImageReader();
558     if (ret < 0) {
559         ALOGE("Failed to get initialize image reader: ret=%d.", ret);
560         return nullptr;
561     }
562 
563     // No need to release the window as AImageReader_delete takes care of it.
564     ANativeWindow* window = testCase.getNativeWindow();
565     if (window == nullptr) {
566         ALOGE("Failed to get native window for the test case.");
567         return nullptr;
568     }
569 
570     return ANativeWindow_toSurface(env, window);
571 }
572