1 /*
2 * Copyright (C) 2016 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 #include <inttypes.h>
18
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "NdkImageReader"
21
22 #include "NdkImagePriv.h"
23 #include "NdkImageReaderPriv.h"
24
25 #include <cutils/atomic.h>
26 #include <utils/Log.h>
27 #include <android_media_Utils.h>
28 #include <android_runtime/android_view_Surface.h>
29 #include <android_runtime/android_hardware_HardwareBuffer.h>
30 #include <grallocusage/GrallocUsageConversion.h>
31
32 using namespace android;
33
34 namespace {
35 // Get an ID that's unique within this process.
createProcessUniqueId()36 static int32_t createProcessUniqueId() {
37 static volatile int32_t globalCounter = 0;
38 return android_atomic_inc(&globalCounter);
39 }
40 }
41
42 const char* AImageReader::kCallbackFpKey = "Callback";
43 const char* AImageReader::kContextKey = "Context";
44 const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
45
46 bool
isSupportedFormat(int32_t format)47 AImageReader::isSupportedFormat(int32_t format) {
48 switch (format) {
49 case AIMAGE_FORMAT_RGBA_8888:
50 case AIMAGE_FORMAT_RGBX_8888:
51 case AIMAGE_FORMAT_RGB_888:
52 case AIMAGE_FORMAT_RGB_565:
53 case AIMAGE_FORMAT_RGBA_FP16:
54 case AIMAGE_FORMAT_YUV_420_888:
55 case AIMAGE_FORMAT_JPEG:
56 case AIMAGE_FORMAT_RAW16:
57 case AIMAGE_FORMAT_RAW_PRIVATE:
58 case AIMAGE_FORMAT_RAW10:
59 case AIMAGE_FORMAT_RAW12:
60 case AIMAGE_FORMAT_DEPTH16:
61 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
62 return true;
63 default:
64 return false;
65 }
66 }
67
68 int
getNumPlanesForFormat(int32_t format)69 AImageReader::getNumPlanesForFormat(int32_t format) {
70 switch (format) {
71 case AIMAGE_FORMAT_YUV_420_888:
72 return 3;
73 case AIMAGE_FORMAT_RGBA_8888:
74 case AIMAGE_FORMAT_RGBX_8888:
75 case AIMAGE_FORMAT_RGB_888:
76 case AIMAGE_FORMAT_RGB_565:
77 case AIMAGE_FORMAT_RGBA_FP16:
78 case AIMAGE_FORMAT_JPEG:
79 case AIMAGE_FORMAT_RAW16:
80 case AIMAGE_FORMAT_RAW_PRIVATE:
81 case AIMAGE_FORMAT_RAW10:
82 case AIMAGE_FORMAT_RAW12:
83 case AIMAGE_FORMAT_DEPTH16:
84 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
85 return 1;
86 default:
87 return -1;
88 }
89 }
90
91 void
onFrameAvailable(const BufferItem &)92 AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
93 Mutex::Autolock _l(mLock);
94 sp<AImageReader> reader = mReader.promote();
95 if (reader == nullptr) {
96 ALOGW("A frame is available after AImageReader closed!");
97 return; // reader has been closed
98 }
99 if (mListener.onImageAvailable == nullptr) {
100 return; // No callback registered
101 }
102
103 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
104 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
105 msg->setPointer(AImageReader::kContextKey, mListener.context);
106 msg->post();
107 }
108
109 media_status_t
setImageListener(AImageReader_ImageListener * listener)110 AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
111 Mutex::Autolock _l(mLock);
112 if (listener == nullptr) {
113 mListener.context = nullptr;
114 mListener.onImageAvailable = nullptr;
115 } else {
116 mListener = *listener;
117 }
118 return AMEDIA_OK;
119 }
120
121 void
onBufferFreed(const wp<GraphicBuffer> & graphicBuffer)122 AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
123 Mutex::Autolock _l(mLock);
124 sp<AImageReader> reader = mReader.promote();
125 if (reader == nullptr) {
126 ALOGW("A frame is available after AImageReader closed!");
127 return; // reader has been closed
128 }
129 if (mListener.onBufferRemoved == nullptr) {
130 return; // No callback registered
131 }
132
133 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
134 if (gBuffer == nullptr) {
135 ALOGW("A buffer being freed has gone away!");
136 return; // buffer is already destroyed
137 }
138
139 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
140 msg->setPointer(
141 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
142 msg->setPointer(AImageReader::kContextKey, mListener.context);
143 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
144 msg->post();
145 }
146
147 media_status_t
setBufferRemovedListener(AImageReader_BufferRemovedListener * listener)148 AImageReader::BufferRemovedListener::setBufferRemovedListener(
149 AImageReader_BufferRemovedListener* listener) {
150 Mutex::Autolock _l(mLock);
151 if (listener == nullptr) {
152 mListener.context = nullptr;
153 mListener.onBufferRemoved = nullptr;
154 } else {
155 mListener = *listener;
156 }
157 return AMEDIA_OK;
158 }
159
160 media_status_t
setImageListenerLocked(AImageReader_ImageListener * listener)161 AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
162 return mFrameListener->setImageListener(listener);
163 }
164
165 media_status_t
setImageListener(AImageReader_ImageListener * listener)166 AImageReader::setImageListener(AImageReader_ImageListener* listener) {
167 Mutex::Autolock _l(mLock);
168 return setImageListenerLocked(listener);
169 }
170
171 media_status_t
setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener * listener)172 AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
173 return mBufferRemovedListener->setBufferRemovedListener(listener);
174 }
175
176 media_status_t
setBufferRemovedListener(AImageReader_BufferRemovedListener * listener)177 AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
178 Mutex::Autolock _l(mLock);
179 return setBufferRemovedListenerLocked(listener);
180 }
181
onMessageReceived(const sp<AMessage> & msg)182 void AImageReader::CallbackHandler::onMessageReceived(
183 const sp<AMessage> &msg) {
184 switch (msg->what()) {
185 case kWhatBufferRemoved:
186 {
187 AImageReader_BufferRemovedCallback onBufferRemoved;
188 void* context;
189 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
190 if (!found || onBufferRemoved == nullptr) {
191 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
192 return;
193 }
194 found = msg->findPointer(kContextKey, &context);
195 if (!found) {
196 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
197 return;
198 }
199 sp<RefBase> bufferToFree;
200 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
201 if (!found || bufferToFree == nullptr) {
202 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
203 return;
204 }
205
206 // TODO(jwcai) Someone from Android graphics team stating this should just be a
207 // static_cast.
208 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
209
210 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
211 // this AImageReader, and the reference will be gone once this function returns.
212 (*onBufferRemoved)(context, mReader, outBuffer);
213 break;
214 }
215 case kWhatImageAvailable:
216 {
217 AImageReader_ImageCallback onImageAvailable;
218 void* context;
219 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
220 if (!found || onImageAvailable == nullptr) {
221 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
222 return;
223 }
224 found = msg->findPointer(kContextKey, &context);
225 if (!found) {
226 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
227 return;
228 }
229 (*onImageAvailable)(context, mReader);
230 break;
231 }
232 default:
233 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
234 break;
235 }
236 }
237
AImageReader(int32_t width,int32_t height,int32_t format,uint64_t usage,int32_t maxImages)238 AImageReader::AImageReader(int32_t width,
239 int32_t height,
240 int32_t format,
241 uint64_t usage,
242 int32_t maxImages)
243 : mWidth(width),
244 mHeight(height),
245 mFormat(format),
246 mUsage(usage),
247 mMaxImages(maxImages),
248 mNumPlanes(getNumPlanesForFormat(format)),
249 mFrameListener(new FrameListener(this)),
250 mBufferRemovedListener(new BufferRemovedListener(this)) {}
251
252 media_status_t
init()253 AImageReader::init() {
254 PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
255 mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
256 mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
257 mHalUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(mUsage);
258
259 sp<IGraphicBufferProducer> gbProducer;
260 sp<IGraphicBufferConsumer> gbConsumer;
261 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
262
263 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
264 mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
265 createProcessUniqueId());
266
267 mBufferItemConsumer =
268 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
269 if (mBufferItemConsumer == nullptr) {
270 ALOGE("Failed to allocate BufferItemConsumer");
271 return AMEDIA_ERROR_UNKNOWN;
272 }
273
274 mProducer = gbProducer;
275 mBufferItemConsumer->setName(consumerName);
276 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
277 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
278
279 status_t res;
280 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
281 if (res != OK) {
282 ALOGE("Failed to set BufferItemConsumer buffer size");
283 return AMEDIA_ERROR_UNKNOWN;
284 }
285 res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
286 if (res != OK) {
287 ALOGE("Failed to set BufferItemConsumer buffer format");
288 return AMEDIA_ERROR_UNKNOWN;
289 }
290 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
291 if (res != OK) {
292 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
293 return AMEDIA_ERROR_UNKNOWN;
294 }
295
296 mSurface = new Surface(mProducer, /*controlledByApp*/true);
297 if (mSurface == nullptr) {
298 ALOGE("Failed to create surface");
299 return AMEDIA_ERROR_UNKNOWN;
300 }
301 mWindow = static_cast<ANativeWindow*>(mSurface.get());
302
303 for (int i = 0; i < mMaxImages; i++) {
304 BufferItem* buffer = new BufferItem;
305 mBuffers.push_back(buffer);
306 }
307
308 mCbLooper = new ALooper;
309 mCbLooper->setName(consumerName.string());
310 res = mCbLooper->start(
311 /*runOnCallingThread*/false,
312 /*canCallJava*/ true,
313 PRIORITY_DEFAULT);
314 if (res != OK) {
315 ALOGE("Failed to start the looper");
316 return AMEDIA_ERROR_UNKNOWN;
317 }
318 mHandler = new CallbackHandler(this);
319 mCbLooper->registerHandler(mHandler);
320
321 return AMEDIA_OK;
322 }
323
~AImageReader()324 AImageReader::~AImageReader() {
325 Mutex::Autolock _l(mLock);
326 AImageReader_ImageListener nullListener = {nullptr, nullptr};
327 setImageListenerLocked(&nullListener);
328
329 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
330 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
331
332 if (mCbLooper != nullptr) {
333 mCbLooper->unregisterHandler(mHandler->id());
334 mCbLooper->stop();
335 }
336 mCbLooper.clear();
337 mHandler.clear();
338
339 // Close all previously acquired images
340 for (auto it = mAcquiredImages.begin();
341 it != mAcquiredImages.end(); it++) {
342 AImage* image = *it;
343 image->close();
344 }
345
346 // Delete Buffer Items
347 for (auto it = mBuffers.begin();
348 it != mBuffers.end(); it++) {
349 delete *it;
350 }
351
352 if (mBufferItemConsumer != nullptr) {
353 mBufferItemConsumer->abandon();
354 mBufferItemConsumer->setFrameAvailableListener(nullptr);
355 }
356 }
357
358 media_status_t
acquireImageLocked(AImage ** image,int * acquireFenceFd)359 AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
360 *image = nullptr;
361 BufferItem* buffer = getBufferItemLocked();
362 if (buffer == nullptr) {
363 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
364 " maxImages buffers");
365 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
366 }
367
368 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
369 bool waitForFence = acquireFenceFd == nullptr;
370 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
371
372 if (res != NO_ERROR) {
373 returnBufferItemLocked(buffer);
374 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
375 if (res == INVALID_OPERATION) {
376 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
377 } else {
378 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
379 __FUNCTION__, strerror(-res), res);
380 return AMEDIA_ERROR_UNKNOWN;
381 }
382 }
383 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
384 }
385
386 const int bufferWidth = getBufferWidth(buffer);
387 const int bufferHeight = getBufferHeight(buffer);
388 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
389 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
390
391 const int readerWidth = mWidth;
392 const int readerHeight = mHeight;
393 const int readerFmt = mHalFormat;
394 const int readerUsage = mHalUsage;
395
396 // Check if the producer buffer configurations match what AImageReader configured. Add some
397 // extra checks for non-opaque formats.
398 if (!isFormatOpaque(readerFmt)) {
399 // Check if the left-top corner of the crop rect is origin, we currently assume this point
400 // is zero, will revisit this once this assumption turns out problematic.
401 Point lt = buffer->mCrop.leftTop();
402 if (lt.x != 0 || lt.y != 0) {
403 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
404 return AMEDIA_ERROR_UNKNOWN;
405 }
406
407 // Check if the producer buffer configurations match what ImageReader configured.
408 ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
409 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
410 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
411
412 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
413 // ImageReader requested has been supported from the producer side.
414 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
415 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
416 "configured: %x",
417 __FUNCTION__, bufferUsage, readerUsage);
418
419 if (readerFmt != bufferFmt) {
420 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
421 // Special casing for when producer switches to a format compatible with flexible
422 // YUV.
423 mHalFormat = bufferFmt;
424 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
425 } else {
426 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
427 // used anywhere yet.
428 mBufferItemConsumer->releaseBuffer(*buffer);
429 returnBufferItemLocked(buffer);
430
431 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
432 __FUNCTION__, bufferFmt, readerFmt);
433
434 return AMEDIA_ERROR_UNKNOWN;
435 }
436 }
437 }
438
439 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
440 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
441 readerWidth, readerHeight, mNumPlanes);
442 } else {
443 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
444 bufferWidth, bufferHeight, mNumPlanes);
445 }
446 mAcquiredImages.push_back(*image);
447
448 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
449 if (acquireFenceFd != nullptr) {
450 *acquireFenceFd = buffer->mFence->dup();
451 }
452
453 return AMEDIA_OK;
454 }
455
456 BufferItem*
getBufferItemLocked()457 AImageReader::getBufferItemLocked() {
458 if (mBuffers.empty()) {
459 return nullptr;
460 }
461 // Return a BufferItem pointer and remove it from the list
462 auto it = mBuffers.begin();
463 BufferItem* buffer = *it;
464 mBuffers.erase(it);
465 return buffer;
466 }
467
468 void
returnBufferItemLocked(BufferItem * buffer)469 AImageReader::returnBufferItemLocked(BufferItem* buffer) {
470 mBuffers.push_back(buffer);
471 }
472
473 void
releaseImageLocked(AImage * image,int releaseFenceFd)474 AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
475 BufferItem* buffer = image->mBuffer;
476 if (buffer == nullptr) {
477 // This should not happen, but is not fatal
478 ALOGW("AImage %p has no buffer!", image);
479 return;
480 }
481
482 int unlockFenceFd = -1;
483 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
484 if (ret < 0) {
485 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
486 return;
487 }
488
489 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
490 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
491 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
492 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
493 returnBufferItemLocked(buffer);
494 image->mBuffer = nullptr;
495
496 bool found = false;
497 // cleanup acquired image list
498 for (auto it = mAcquiredImages.begin();
499 it != mAcquiredImages.end(); it++) {
500 AImage* readerCopy = *it;
501 if (readerCopy == image) {
502 found = true;
503 mAcquiredImages.erase(it);
504 break;
505 }
506 }
507 if (!found) {
508 ALOGE("Error: AImage %p is not generated by AImageReader %p",
509 image, this);
510 }
511 }
512
513 int
getBufferWidth(BufferItem * buffer)514 AImageReader::getBufferWidth(BufferItem* buffer) {
515 if (buffer == NULL) return -1;
516
517 if (!buffer->mCrop.isEmpty()) {
518 return buffer->mCrop.getWidth();
519 }
520
521 return buffer->mGraphicBuffer->getWidth();
522 }
523
524 int
getBufferHeight(BufferItem * buffer)525 AImageReader::getBufferHeight(BufferItem* buffer) {
526 if (buffer == NULL) return -1;
527
528 if (!buffer->mCrop.isEmpty()) {
529 return buffer->mCrop.getHeight();
530 }
531
532 return buffer->mGraphicBuffer->getHeight();
533 }
534
535 media_status_t
acquireNextImage(AImage ** image,int * acquireFenceFd)536 AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
537 Mutex::Autolock _l(mLock);
538 return acquireImageLocked(image, acquireFenceFd);
539 }
540
541 media_status_t
acquireLatestImage(AImage ** image,int * acquireFenceFd)542 AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
543 if (image == nullptr) {
544 return AMEDIA_ERROR_INVALID_PARAMETER;
545 }
546 Mutex::Autolock _l(mLock);
547 *image = nullptr;
548 AImage* prevImage = nullptr;
549 AImage* nextImage = nullptr;
550 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
551 if (prevImage == nullptr) {
552 return ret;
553 }
554 for (;;) {
555 ret = acquireImageLocked(&nextImage, acquireFenceFd);
556 if (nextImage == nullptr) {
557 *image = prevImage;
558 return AMEDIA_OK;
559 }
560
561 if (acquireFenceFd == nullptr) {
562 // No need for release fence here since the prevImage is unused and acquireImageLocked
563 // has already waited for acquired fence to be signaled.
564 prevImage->close();
565 } else {
566 // Use the acquire fence as release fence, so that producer can wait before trying to
567 // refill the buffer.
568 prevImage->close(*acquireFenceFd);
569 }
570 prevImage->free();
571 prevImage = nextImage;
572 nextImage = nullptr;
573 }
574 }
575
576 EXPORT
AImageReader_new(int32_t width,int32_t height,int32_t format,int32_t maxImages,AImageReader ** reader)577 media_status_t AImageReader_new(
578 int32_t width, int32_t height, int32_t format, int32_t maxImages,
579 /*out*/AImageReader** reader) {
580 ALOGV("%s", __FUNCTION__);
581 return AImageReader_newWithUsage(
582 width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
583 }
584
585 EXPORT
AImageReader_newWithUsage(int32_t width,int32_t height,int32_t format,uint64_t usage,int32_t maxImages,AImageReader ** reader)586 media_status_t AImageReader_newWithUsage(
587 int32_t width, int32_t height, int32_t format, uint64_t usage,
588 int32_t maxImages, /*out*/ AImageReader** reader) {
589 ALOGV("%s", __FUNCTION__);
590
591 if (width < 1 || height < 1) {
592 ALOGE("%s: image dimension must be positive: w:%d h:%d",
593 __FUNCTION__, width, height);
594 return AMEDIA_ERROR_INVALID_PARAMETER;
595 }
596
597 if (maxImages < 1) {
598 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
599 __FUNCTION__, maxImages);
600 return AMEDIA_ERROR_INVALID_PARAMETER;
601 }
602
603 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
604 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
605 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
606 return AMEDIA_ERROR_INVALID_PARAMETER;
607 }
608
609 if (!AImageReader::isSupportedFormat(format)) {
610 ALOGE("%s: format %d is not supported by AImageReader",
611 __FUNCTION__, format);
612 return AMEDIA_ERROR_INVALID_PARAMETER;
613 }
614
615 if (reader == nullptr) {
616 ALOGE("%s: reader argument is null", __FUNCTION__);
617 return AMEDIA_ERROR_INVALID_PARAMETER;
618 }
619
620 AImageReader* tmpReader = new AImageReader(
621 width, height, format, usage, maxImages);
622 if (tmpReader == nullptr) {
623 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
624 return AMEDIA_ERROR_UNKNOWN;
625 }
626 media_status_t ret = tmpReader->init();
627 if (ret != AMEDIA_OK) {
628 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
629 delete tmpReader;
630 return ret;
631 }
632 *reader = tmpReader;
633 (*reader)->incStrong((void*) AImageReader_new);
634 return AMEDIA_OK;
635 }
636
637 EXPORT
AImageReader_delete(AImageReader * reader)638 void AImageReader_delete(AImageReader* reader) {
639 ALOGV("%s", __FUNCTION__);
640 if (reader != nullptr) {
641 reader->decStrong((void*) AImageReader_delete);
642 }
643 return;
644 }
645
646 EXPORT
AImageReader_getWindow(AImageReader * reader,ANativeWindow ** window)647 media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
648 ALOGE("%s", __FUNCTION__);
649 if (reader == nullptr || window == nullptr) {
650 ALOGE("%s: invalid argument. reader %p, window %p",
651 __FUNCTION__, reader, window);
652 return AMEDIA_ERROR_INVALID_PARAMETER;
653 }
654 *window = reader->getWindow();
655 return AMEDIA_OK;
656 }
657
658 EXPORT
AImageReader_getWidth(const AImageReader * reader,int32_t * width)659 media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
660 ALOGV("%s", __FUNCTION__);
661 if (reader == nullptr || width == nullptr) {
662 ALOGE("%s: invalid argument. reader %p, width %p",
663 __FUNCTION__, reader, width);
664 return AMEDIA_ERROR_INVALID_PARAMETER;
665 }
666 *width = reader->getWidth();
667 return AMEDIA_OK;
668 }
669
670 EXPORT
AImageReader_getHeight(const AImageReader * reader,int32_t * height)671 media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
672 ALOGV("%s", __FUNCTION__);
673 if (reader == nullptr || height == nullptr) {
674 ALOGE("%s: invalid argument. reader %p, height %p",
675 __FUNCTION__, reader, height);
676 return AMEDIA_ERROR_INVALID_PARAMETER;
677 }
678 *height = reader->getHeight();
679 return AMEDIA_OK;
680 }
681
682 EXPORT
AImageReader_getFormat(const AImageReader * reader,int32_t * format)683 media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
684 ALOGV("%s", __FUNCTION__);
685 if (reader == nullptr || format == nullptr) {
686 ALOGE("%s: invalid argument. reader %p, format %p",
687 __FUNCTION__, reader, format);
688 return AMEDIA_ERROR_INVALID_PARAMETER;
689 }
690 *format = reader->getFormat();
691 return AMEDIA_OK;
692 }
693
694 EXPORT
AImageReader_getMaxImages(const AImageReader * reader,int32_t * maxImages)695 media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
696 ALOGV("%s", __FUNCTION__);
697 if (reader == nullptr || maxImages == nullptr) {
698 ALOGE("%s: invalid argument. reader %p, maxImages %p",
699 __FUNCTION__, reader, maxImages);
700 return AMEDIA_ERROR_INVALID_PARAMETER;
701 }
702 *maxImages = reader->getMaxImages();
703 return AMEDIA_OK;
704 }
705
706 EXPORT
AImageReader_acquireNextImage(AImageReader * reader,AImage ** image)707 media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
708 ALOGV("%s", __FUNCTION__);
709 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
710 }
711
712 EXPORT
AImageReader_acquireLatestImage(AImageReader * reader,AImage ** image)713 media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
714 ALOGV("%s", __FUNCTION__);
715 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
716 }
717
718 EXPORT
AImageReader_acquireNextImageAsync(AImageReader * reader,AImage ** image,int * acquireFenceFd)719 media_status_t AImageReader_acquireNextImageAsync(
720 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
721 ALOGV("%s", __FUNCTION__);
722 if (reader == nullptr || image == nullptr) {
723 ALOGE("%s: invalid argument. reader %p, image %p",
724 __FUNCTION__, reader, image);
725 return AMEDIA_ERROR_INVALID_PARAMETER;
726 }
727 return reader->acquireNextImage(image, acquireFenceFd);
728 }
729
730 EXPORT
AImageReader_acquireLatestImageAsync(AImageReader * reader,AImage ** image,int * acquireFenceFd)731 media_status_t AImageReader_acquireLatestImageAsync(
732 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
733 ALOGV("%s", __FUNCTION__);
734 if (reader == nullptr || image == nullptr) {
735 ALOGE("%s: invalid argument. reader %p, image %p",
736 __FUNCTION__, reader, image);
737 return AMEDIA_ERROR_INVALID_PARAMETER;
738 }
739 return reader->acquireLatestImage(image, acquireFenceFd);
740 }
741
742 EXPORT
AImageReader_setImageListener(AImageReader * reader,AImageReader_ImageListener * listener)743 media_status_t AImageReader_setImageListener(
744 AImageReader* reader, AImageReader_ImageListener* listener) {
745 ALOGV("%s", __FUNCTION__);
746 if (reader == nullptr) {
747 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
748 return AMEDIA_ERROR_INVALID_PARAMETER;
749 }
750
751 reader->setImageListener(listener);
752 return AMEDIA_OK;
753 }
754
755 EXPORT
AImageReader_setBufferRemovedListener(AImageReader * reader,AImageReader_BufferRemovedListener * listener)756 media_status_t AImageReader_setBufferRemovedListener(
757 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
758 ALOGV("%s", __FUNCTION__);
759 if (reader == nullptr) {
760 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
761 return AMEDIA_ERROR_INVALID_PARAMETER;
762 }
763
764 reader->setBufferRemovedListener(listener);
765 return AMEDIA_OK;
766 }
767