blob: c0ceb3d70b8479918a96592b79e474440ec9d030 [file] [log] [blame]
Yin-Chia Yehc3603822016-01-18 22:11:19 -08001/*
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"
Jayant Chowdhary5fa12762019-03-13 15:01:58 -070024#include <private/media/NdkImage.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080025
Mathias Agopian05d19b02017-02-28 16:28:19 -080026#include <cutils/atomic.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080027#include <utils/Log.h>
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080028#include <android_media_Utils.h>
Jooyung Han86cbf712019-02-21 15:25:02 +090029#include <ui/PublicFormat.h>
Jooyung Han27d84b72019-02-21 15:12:59 +090030#include <private/android/AHardwareBufferHelpers.h>
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -070031#include <grallocusage/GrallocUsageConversion.h>
Chong Zhang0fe4c472019-04-08 21:51:46 +000032#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080033
34using namespace android;
35
36namespace {
37 // Get an ID that's unique within this process.
38 static int32_t createProcessUniqueId() {
39 static volatile int32_t globalCounter = 0;
40 return android_atomic_inc(&globalCounter);
41 }
42}
43
44const char* AImageReader::kCallbackFpKey = "Callback";
45const char* AImageReader::kContextKey = "Context";
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080046const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
Yin-Chia Yehc3603822016-01-18 22:11:19 -080047
Jayant Chowdhary249e1f22018-09-24 15:07:45 -070048static constexpr int kWindowHalTokenSizeMax = 256;
49
50static native_handle_t *convertHalTokenToNativeHandle(const HalToken &halToken);
51
Yin-Chia Yehc3603822016-01-18 22:11:19 -080052bool
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070053AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
54 // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
55 // AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN (0x6) is sufficient as it implies
56 // AHARDWAREBUFFER_USAGE_CPU_READ (0x2).
57 bool hasCpuUsage = usage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080058 switch (format) {
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080059 case AIMAGE_FORMAT_RGBA_8888:
60 case AIMAGE_FORMAT_RGBX_8888:
61 case AIMAGE_FORMAT_RGB_888:
62 case AIMAGE_FORMAT_RGB_565:
63 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080064 case AIMAGE_FORMAT_YUV_420_888:
65 case AIMAGE_FORMAT_JPEG:
66 case AIMAGE_FORMAT_RAW16:
Jayant Chowdhary5fa12762019-03-13 15:01:58 -070067 case AIMAGE_FORMAT_RAW_DEPTH:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080068 case AIMAGE_FORMAT_RAW_PRIVATE:
69 case AIMAGE_FORMAT_RAW10:
70 case AIMAGE_FORMAT_RAW12:
71 case AIMAGE_FORMAT_DEPTH16:
72 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
Shuzhen Wang1cfbbec2018-10-08 13:55:28 -070073 case AIMAGE_FORMAT_Y8:
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080074 case AIMAGE_FORMAT_HEIC:
Emilian Peev44df34d2019-02-12 09:30:15 -080075 case AIMAGE_FORMAT_DEPTH_JPEG:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080076 return true;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070077 case AIMAGE_FORMAT_PRIVATE:
78 // For private format, cpu usage is prohibited.
79 return !hasCpuUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080080 default:
81 return false;
82 }
83}
84
85int
86AImageReader::getNumPlanesForFormat(int32_t format) {
87 switch (format) {
88 case AIMAGE_FORMAT_YUV_420_888:
89 return 3;
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080090 case AIMAGE_FORMAT_RGBA_8888:
91 case AIMAGE_FORMAT_RGBX_8888:
92 case AIMAGE_FORMAT_RGB_888:
93 case AIMAGE_FORMAT_RGB_565:
94 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080095 case AIMAGE_FORMAT_JPEG:
96 case AIMAGE_FORMAT_RAW16:
Jayant Chowdhary5fa12762019-03-13 15:01:58 -070097 case AIMAGE_FORMAT_RAW_DEPTH:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080098 case AIMAGE_FORMAT_RAW_PRIVATE:
99 case AIMAGE_FORMAT_RAW10:
100 case AIMAGE_FORMAT_RAW12:
101 case AIMAGE_FORMAT_DEPTH16:
102 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
Shuzhen Wang1cfbbec2018-10-08 13:55:28 -0700103 case AIMAGE_FORMAT_Y8:
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800104 case AIMAGE_FORMAT_HEIC:
Emilian Peev44df34d2019-02-12 09:30:15 -0800105 case AIMAGE_FORMAT_DEPTH_JPEG:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800106 return 1;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700107 case AIMAGE_FORMAT_PRIVATE:
108 return 0;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800109 default:
110 return -1;
111 }
112}
113
114void
115AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800116 sp<AImageReader> reader = mReader.promote();
117 if (reader == nullptr) {
118 ALOGW("A frame is available after AImageReader closed!");
119 return; // reader has been closed
120 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700121 Mutex::Autolock _l(mLock);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800122 if (mListener.onImageAvailable == nullptr) {
123 return; // No callback registered
124 }
125
126 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
127 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
128 msg->setPointer(AImageReader::kContextKey, mListener.context);
129 msg->post();
130}
131
132media_status_t
133AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
134 Mutex::Autolock _l(mLock);
135 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700136 mListener.context = nullptr;
137 mListener.onImageAvailable = nullptr;
138 } else {
139 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800140 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800141 return AMEDIA_OK;
142}
143
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800144void
145AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800146 sp<AImageReader> reader = mReader.promote();
147 if (reader == nullptr) {
148 ALOGW("A frame is available after AImageReader closed!");
149 return; // reader has been closed
150 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700151 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800152 if (mListener.onBufferRemoved == nullptr) {
153 return; // No callback registered
154 }
155
156 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
157 if (gBuffer == nullptr) {
158 ALOGW("A buffer being freed has gone away!");
159 return; // buffer is already destroyed
160 }
161
162 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
163 msg->setPointer(
164 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
165 msg->setPointer(AImageReader::kContextKey, mListener.context);
166 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
167 msg->post();
168}
169
170media_status_t
171AImageReader::BufferRemovedListener::setBufferRemovedListener(
172 AImageReader_BufferRemovedListener* listener) {
173 Mutex::Autolock _l(mLock);
174 if (listener == nullptr) {
175 mListener.context = nullptr;
176 mListener.onBufferRemoved = nullptr;
177 } else {
178 mListener = *listener;
179 }
180 return AMEDIA_OK;
181}
182
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800183media_status_t
184AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
185 return mFrameListener->setImageListener(listener);
186}
187
188media_status_t
189AImageReader::setImageListener(AImageReader_ImageListener* listener) {
190 Mutex::Autolock _l(mLock);
191 return setImageListenerLocked(listener);
192}
193
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800194media_status_t
195AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
196 return mBufferRemovedListener->setBufferRemovedListener(listener);
197}
198
199media_status_t
200AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
201 Mutex::Autolock _l(mLock);
202 return setBufferRemovedListenerLocked(listener);
203}
204
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800205void AImageReader::CallbackHandler::onMessageReceived(
206 const sp<AMessage> &msg) {
207 switch (msg->what()) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800208 case kWhatBufferRemoved:
209 {
210 AImageReader_BufferRemovedCallback onBufferRemoved;
211 void* context;
212 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
213 if (!found || onBufferRemoved == nullptr) {
214 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
215 return;
216 }
217 found = msg->findPointer(kContextKey, &context);
218 if (!found) {
219 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
220 return;
221 }
222 sp<RefBase> bufferToFree;
223 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
224 if (!found || bufferToFree == nullptr) {
225 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
226 return;
227 }
228
229 // TODO(jwcai) Someone from Android graphics team stating this should just be a
230 // static_cast.
231 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
232
233 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
234 // this AImageReader, and the reference will be gone once this function returns.
235 (*onBufferRemoved)(context, mReader, outBuffer);
236 break;
237 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800238 case kWhatImageAvailable:
239 {
240 AImageReader_ImageCallback onImageAvailable;
241 void* context;
242 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
243 if (!found || onImageAvailable == nullptr) {
244 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
245 return;
246 }
247 found = msg->findPointer(kContextKey, &context);
248 if (!found) {
249 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
250 return;
251 }
252 (*onImageAvailable)(context, mReader);
253 break;
254 }
255 default:
256 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
257 break;
258 }
259}
260
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800261AImageReader::AImageReader(int32_t width,
262 int32_t height,
263 int32_t format,
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700264 uint64_t usage,
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800265 int32_t maxImages)
266 : mWidth(width),
267 mHeight(height),
268 mFormat(format),
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700269 mUsage(usage),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800270 mMaxImages(maxImages),
271 mNumPlanes(getNumPlanesForFormat(format)),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800272 mFrameListener(new FrameListener(this)),
273 mBufferRemovedListener(new BufferRemovedListener(this)) {}
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800274
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700275AImageReader::~AImageReader() {
276 Mutex::Autolock _l(mLock);
277 LOG_FATAL_IF("AImageReader not closed before destruction", mIsClosed != true);
278}
279
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800280media_status_t
281AImageReader::init() {
282 PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
Jooyung Han86cbf712019-02-21 15:25:02 +0900283 mHalFormat = mapPublicFormatToHalFormat(publicFormat);
284 mHalDataSpace = mapPublicFormatToHalDataspace(publicFormat);
Jooyung Han27d84b72019-02-21 15:12:59 +0900285 mHalUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800286
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800287 sp<IGraphicBufferProducer> gbProducer;
288 sp<IGraphicBufferConsumer> gbConsumer;
289 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
290
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700291 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
292 mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800293 createProcessUniqueId());
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800294
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800295 mBufferItemConsumer =
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800296 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800297 if (mBufferItemConsumer == nullptr) {
298 ALOGE("Failed to allocate BufferItemConsumer");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800299 return AMEDIA_ERROR_UNKNOWN;
300 }
301
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800302 mProducer = gbProducer;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800303 mBufferItemConsumer->setName(consumerName);
304 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800305 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800306
307 status_t res;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800308 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800309 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800310 ALOGE("Failed to set BufferItemConsumer buffer size");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800311 return AMEDIA_ERROR_UNKNOWN;
312 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800313 res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800314 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800315 ALOGE("Failed to set BufferItemConsumer buffer format");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800316 return AMEDIA_ERROR_UNKNOWN;
317 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800318 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800319 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800320 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800321 return AMEDIA_ERROR_UNKNOWN;
322 }
Khushalff20fd42019-01-22 15:31:00 -0800323 if (mUsage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
324 gbConsumer->setConsumerIsProtected(true);
325 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800326
327 mSurface = new Surface(mProducer, /*controlledByApp*/true);
328 if (mSurface == nullptr) {
329 ALOGE("Failed to create surface");
330 return AMEDIA_ERROR_UNKNOWN;
331 }
332 mWindow = static_cast<ANativeWindow*>(mSurface.get());
333
334 for (int i = 0; i < mMaxImages; i++) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800335 BufferItem* buffer = new BufferItem;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800336 mBuffers.push_back(buffer);
337 }
338
339 mCbLooper = new ALooper;
340 mCbLooper->setName(consumerName.string());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800341 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800342 /*runOnCallingThread*/false,
343 /*canCallJava*/ true,
344 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800345 if (res != OK) {
346 ALOGE("Failed to start the looper");
347 return AMEDIA_ERROR_UNKNOWN;
348 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800349 mHandler = new CallbackHandler(this);
350 mCbLooper->registerHandler(mHandler);
351
352 return AMEDIA_OK;
353}
354
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700355void AImageReader::close() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800356 Mutex::Autolock _l(mLock);
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700357 if (mIsClosed) {
358 return;
359 }
360 mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800361 AImageReader_ImageListener nullListener = {nullptr, nullptr};
362 setImageListenerLocked(&nullListener);
363
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800364 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
365 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
366
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800367 if (mCbLooper != nullptr) {
368 mCbLooper->unregisterHandler(mHandler->id());
369 mCbLooper->stop();
370 }
371 mCbLooper.clear();
372 mHandler.clear();
373
374 // Close all previously acquired images
375 for (auto it = mAcquiredImages.begin();
376 it != mAcquiredImages.end(); it++) {
377 AImage* image = *it;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800378 Mutex::Autolock _l(image->mLock);
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800379 // Do not alter mAcquiredImages while we are iterating on it
380 releaseImageLocked(image, /*releaseFenceFd*/-1, /*clearCache*/false);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800381 }
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800382 mAcquiredImages.clear();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800383
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800384 // Delete Buffer Items
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800385 for (auto it = mBuffers.begin();
386 it != mBuffers.end(); it++) {
387 delete *it;
388 }
389
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800390 if (mBufferItemConsumer != nullptr) {
391 mBufferItemConsumer->abandon();
392 mBufferItemConsumer->setFrameAvailableListener(nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800393 }
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700394
395 if (mWindowHandle != nullptr) {
396 int size = mWindowHandle->data[0];
397 hidl_vec<uint8_t> halToken;
398 halToken.setToExternal(
399 reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
400 deleteHalToken(halToken);
401 native_handle_delete(mWindowHandle);
402 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800403}
404
405media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800406AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800407 *image = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800408 BufferItem* buffer = getBufferItemLocked();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800409 if (buffer == nullptr) {
410 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
411 " maxImages buffers");
412 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
413 }
414
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800415 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
416 bool waitForFence = acquireFenceFd == nullptr;
417 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
418
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800419 if (res != NO_ERROR) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800420 returnBufferItemLocked(buffer);
421 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
422 if (res == INVALID_OPERATION) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800423 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
424 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800425 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
426 __FUNCTION__, strerror(-res), res);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800427 return AMEDIA_ERROR_UNKNOWN;
428 }
429 }
430 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
431 }
432
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800433 const int bufferWidth = getBufferWidth(buffer);
434 const int bufferHeight = getBufferHeight(buffer);
435 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800436 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800437
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800438 const int readerWidth = mWidth;
439 const int readerHeight = mHeight;
440 const int readerFmt = mHalFormat;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800441 const int readerUsage = mHalUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800442
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800443 // Check if the producer buffer configurations match what AImageReader configured. Add some
444 // extra checks for non-opaque formats.
445 if (!isFormatOpaque(readerFmt)) {
446 // Check if the left-top corner of the crop rect is origin, we currently assume this point
447 // is zero, will revisit this once this assumption turns out problematic.
448 Point lt = buffer->mCrop.leftTop();
449 if (lt.x != 0 || lt.y != 0) {
450 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800451 return AMEDIA_ERROR_UNKNOWN;
452 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800453
454 // Check if the producer buffer configurations match what ImageReader configured.
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -0700455 ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
456 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
457 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800458
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800459 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
460 // ImageReader requested has been supported from the producer side.
461 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
462 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
463 "configured: %x",
464 __FUNCTION__, bufferUsage, readerUsage);
465
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800466 if (readerFmt != bufferFmt) {
467 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
468 // Special casing for when producer switches to a format compatible with flexible
469 // YUV.
470 mHalFormat = bufferFmt;
471 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
472 } else {
473 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
474 // used anywhere yet.
475 mBufferItemConsumer->releaseBuffer(*buffer);
476 returnBufferItemLocked(buffer);
477
478 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
479 __FUNCTION__, bufferFmt, readerFmt);
480
481 return AMEDIA_ERROR_UNKNOWN;
482 }
483 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800484 }
485
486 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700487 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800488 readerWidth, readerHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800489 } else {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700490 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800491 bufferWidth, bufferHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800492 }
493 mAcquiredImages.push_back(*image);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800494
495 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
496 if (acquireFenceFd != nullptr) {
497 *acquireFenceFd = buffer->mFence->dup();
498 }
499
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800500 return AMEDIA_OK;
501}
502
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800503BufferItem*
504AImageReader::getBufferItemLocked() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800505 if (mBuffers.empty()) {
506 return nullptr;
507 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800508 // Return a BufferItem pointer and remove it from the list
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800509 auto it = mBuffers.begin();
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800510 BufferItem* buffer = *it;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800511 mBuffers.erase(it);
512 return buffer;
513}
514
515void
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800516AImageReader::returnBufferItemLocked(BufferItem* buffer) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800517 mBuffers.push_back(buffer);
518}
519
520void
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800521AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd, bool clearCache) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800522 BufferItem* buffer = image->mBuffer;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800523 if (buffer == nullptr) {
524 // This should not happen, but is not fatal
525 ALOGW("AImage %p has no buffer!", image);
526 return;
527 }
528
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800529 int unlockFenceFd = -1;
530 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800531 if (ret < 0) {
532 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
533 return;
534 }
535
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800536 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
537 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
538 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
539 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800540 returnBufferItemLocked(buffer);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800541 image->mBuffer = nullptr;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800542 image->mLockedBuffer = nullptr;
543 image->mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800544
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800545 if (!clearCache) {
546 return;
547 }
548
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800549 bool found = false;
550 // cleanup acquired image list
551 for (auto it = mAcquiredImages.begin();
552 it != mAcquiredImages.end(); it++) {
553 AImage* readerCopy = *it;
554 if (readerCopy == image) {
555 found = true;
556 mAcquiredImages.erase(it);
557 break;
558 }
559 }
560 if (!found) {
561 ALOGE("Error: AImage %p is not generated by AImageReader %p",
562 image, this);
563 }
564}
565
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700566media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
567 if (mWindowHandle != nullptr) {
568 *handle = mWindowHandle;
569 return AMEDIA_OK;
570 }
571 sp<HGraphicBufferProducer> hgbp =
572 new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
573 HalToken halToken;
574 if (!createHalToken(hgbp, &halToken)) {
575 return AMEDIA_ERROR_UNKNOWN;
576 }
577 mWindowHandle = convertHalTokenToNativeHandle(halToken);
578 if (!mWindowHandle) {
579 return AMEDIA_ERROR_UNKNOWN;
580 }
581 *handle = mWindowHandle;
582 return AMEDIA_OK;
583}
584
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800585int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800586AImageReader::getBufferWidth(BufferItem* buffer) {
587 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800588
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800589 if (!buffer->mCrop.isEmpty()) {
590 return buffer->mCrop.getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800591 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800592
593 return buffer->mGraphicBuffer->getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800594}
595
596int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800597AImageReader::getBufferHeight(BufferItem* buffer) {
598 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800599
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800600 if (!buffer->mCrop.isEmpty()) {
601 return buffer->mCrop.getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800602 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800603
604 return buffer->mGraphicBuffer->getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800605}
606
607media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800608AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800609 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800610 return acquireImageLocked(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800611}
612
613media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800614AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800615 if (image == nullptr) {
616 return AMEDIA_ERROR_INVALID_PARAMETER;
617 }
618 Mutex::Autolock _l(mLock);
619 *image = nullptr;
620 AImage* prevImage = nullptr;
621 AImage* nextImage = nullptr;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800622 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800623 if (prevImage == nullptr) {
624 return ret;
625 }
626 for (;;) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800627 ret = acquireImageLocked(&nextImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800628 if (nextImage == nullptr) {
629 *image = prevImage;
630 return AMEDIA_OK;
631 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800632
633 if (acquireFenceFd == nullptr) {
634 // No need for release fence here since the prevImage is unused and acquireImageLocked
635 // has already waited for acquired fence to be signaled.
636 prevImage->close();
637 } else {
638 // Use the acquire fence as release fence, so that producer can wait before trying to
639 // refill the buffer.
640 prevImage->close(*acquireFenceFd);
641 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800642 prevImage->free();
643 prevImage = nextImage;
644 nextImage = nullptr;
645 }
646}
647
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700648static native_handle_t *convertHalTokenToNativeHandle(
649 const HalToken &halToken) {
650 // We attempt to store halToken in the ints of the native_handle_t after its
651 // size. The first int stores the size of the token. We store this in an int
652 // to avoid alignment issues where size_t and int do not have the same
653 // alignment.
654 size_t nhDataByteSize = halToken.size();
655 if (nhDataByteSize > kWindowHalTokenSizeMax) {
656 // The size of the token isn't reasonable..
657 return nullptr;
658 }
659 size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
660
661 // We don't check for overflow, whether numInts can fit in an int, since we
662 // expect kWindowHalTokenSizeMax to be a reasonable limit.
663 // create a native_handle_t with 0 numFds and numInts number of ints.
664 native_handle_t *nh =
665 native_handle_create(0, numInts);
666 if (!nh) {
667 return nullptr;
668 }
669 // Store the size of the token in the first int.
670 nh->data[0] = nhDataByteSize;
671 memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
672 return nh;
673}
674
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800675EXPORT
676media_status_t AImageReader_new(
677 int32_t width, int32_t height, int32_t format, int32_t maxImages,
678 /*out*/AImageReader** reader) {
679 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800680 return AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700681 width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800682}
683
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700684extern "C" {
685
686EXPORT
687media_status_t AImageReader_getWindowNativeHandle(
688 AImageReader *reader, /*out*/native_handle_t **handle) {
689 if (reader == nullptr || handle == nullptr) {
690 return AMEDIA_ERROR_INVALID_PARAMETER;
691 }
692 return reader->getWindowNativeHandle(handle);
693}
694
695} //extern "C"
696
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800697EXPORT
698media_status_t AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700699 int32_t width, int32_t height, int32_t format, uint64_t usage,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800700 int32_t maxImages, /*out*/ AImageReader** reader) {
701 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800702
703 if (width < 1 || height < 1) {
704 ALOGE("%s: image dimension must be positive: w:%d h:%d",
705 __FUNCTION__, width, height);
706 return AMEDIA_ERROR_INVALID_PARAMETER;
707 }
708
709 if (maxImages < 1) {
710 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
711 __FUNCTION__, maxImages);
712 return AMEDIA_ERROR_INVALID_PARAMETER;
713 }
714
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800715 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
716 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
717 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
718 return AMEDIA_ERROR_INVALID_PARAMETER;
719 }
720
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700721 if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
722 ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
723 __FUNCTION__, format, usage);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800724 return AMEDIA_ERROR_INVALID_PARAMETER;
725 }
726
727 if (reader == nullptr) {
728 ALOGE("%s: reader argument is null", __FUNCTION__);
729 return AMEDIA_ERROR_INVALID_PARAMETER;
730 }
731
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800732 AImageReader* tmpReader = new AImageReader(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700733 width, height, format, usage, maxImages);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800734 if (tmpReader == nullptr) {
735 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
736 return AMEDIA_ERROR_UNKNOWN;
737 }
738 media_status_t ret = tmpReader->init();
739 if (ret != AMEDIA_OK) {
740 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
741 delete tmpReader;
742 return ret;
743 }
744 *reader = tmpReader;
745 (*reader)->incStrong((void*) AImageReader_new);
746 return AMEDIA_OK;
747}
748
749EXPORT
750void AImageReader_delete(AImageReader* reader) {
751 ALOGV("%s", __FUNCTION__);
752 if (reader != nullptr) {
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700753 reader->close();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800754 reader->decStrong((void*) AImageReader_delete);
755 }
756 return;
757}
758
759EXPORT
760media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
Yin-Chia Yehe2ded212017-11-08 15:51:02 -0800761 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800762 if (reader == nullptr || window == nullptr) {
763 ALOGE("%s: invalid argument. reader %p, window %p",
764 __FUNCTION__, reader, window);
765 return AMEDIA_ERROR_INVALID_PARAMETER;
766 }
767 *window = reader->getWindow();
768 return AMEDIA_OK;
769}
770
771EXPORT
772media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
773 ALOGV("%s", __FUNCTION__);
774 if (reader == nullptr || width == nullptr) {
775 ALOGE("%s: invalid argument. reader %p, width %p",
776 __FUNCTION__, reader, width);
777 return AMEDIA_ERROR_INVALID_PARAMETER;
778 }
779 *width = reader->getWidth();
780 return AMEDIA_OK;
781}
782
783EXPORT
784media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
785 ALOGV("%s", __FUNCTION__);
786 if (reader == nullptr || height == nullptr) {
787 ALOGE("%s: invalid argument. reader %p, height %p",
788 __FUNCTION__, reader, height);
789 return AMEDIA_ERROR_INVALID_PARAMETER;
790 }
791 *height = reader->getHeight();
792 return AMEDIA_OK;
793}
794
795EXPORT
796media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
797 ALOGV("%s", __FUNCTION__);
798 if (reader == nullptr || format == nullptr) {
799 ALOGE("%s: invalid argument. reader %p, format %p",
800 __FUNCTION__, reader, format);
801 return AMEDIA_ERROR_INVALID_PARAMETER;
802 }
803 *format = reader->getFormat();
804 return AMEDIA_OK;
805}
806
807EXPORT
808media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
809 ALOGV("%s", __FUNCTION__);
810 if (reader == nullptr || maxImages == nullptr) {
811 ALOGE("%s: invalid argument. reader %p, maxImages %p",
812 __FUNCTION__, reader, maxImages);
813 return AMEDIA_ERROR_INVALID_PARAMETER;
814 }
815 *maxImages = reader->getMaxImages();
816 return AMEDIA_OK;
817}
818
819EXPORT
820media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
821 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800822 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800823}
824
825EXPORT
826media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
827 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800828 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
829}
830
831EXPORT
832media_status_t AImageReader_acquireNextImageAsync(
833 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
834 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800835 if (reader == nullptr || image == nullptr) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800836 ALOGE("%s: invalid argument. reader %p, image %p",
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800837 __FUNCTION__, reader, image);
838 return AMEDIA_ERROR_INVALID_PARAMETER;
839 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800840 return reader->acquireNextImage(image, acquireFenceFd);
841}
842
843EXPORT
844media_status_t AImageReader_acquireLatestImageAsync(
845 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
846 ALOGV("%s", __FUNCTION__);
847 if (reader == nullptr || image == nullptr) {
848 ALOGE("%s: invalid argument. reader %p, image %p",
849 __FUNCTION__, reader, image);
850 return AMEDIA_ERROR_INVALID_PARAMETER;
851 }
852 return reader->acquireLatestImage(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800853}
854
855EXPORT
856media_status_t AImageReader_setImageListener(
857 AImageReader* reader, AImageReader_ImageListener* listener) {
858 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700859 if (reader == nullptr) {
860 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800861 return AMEDIA_ERROR_INVALID_PARAMETER;
862 }
863
864 reader->setImageListener(listener);
865 return AMEDIA_OK;
866}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800867
868EXPORT
869media_status_t AImageReader_setBufferRemovedListener(
870 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
871 ALOGV("%s", __FUNCTION__);
872 if (reader == nullptr) {
873 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
874 return AMEDIA_ERROR_INVALID_PARAMETER;
875 }
876
877 reader->setBufferRemovedListener(listener);
878 return AMEDIA_OK;
879}