blob: 5d8f0b84515cb37204589f2afb38540d6666bdef [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"
24
Mathias Agopian05d19b02017-02-28 16:28:19 -080025#include <cutils/atomic.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080026#include <utils/Log.h>
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080027#include <android_media_Utils.h>
Jooyung Han86cbf712019-02-21 15:25:02 +090028#include <ui/PublicFormat.h>
Jooyung Han27d84b72019-02-21 15:12:59 +090029#include <private/android/AHardwareBufferHelpers.h>
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -070030#include <grallocusage/GrallocUsageConversion.h>
Chong Zhang0fe4c472019-04-08 21:51:46 +000031#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080032
33using namespace android;
34
35namespace {
36 // Get an ID that's unique within this process.
37 static int32_t createProcessUniqueId() {
38 static volatile int32_t globalCounter = 0;
39 return android_atomic_inc(&globalCounter);
40 }
41}
42
43const char* AImageReader::kCallbackFpKey = "Callback";
44const char* AImageReader::kContextKey = "Context";
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080045const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
Yin-Chia Yehc3603822016-01-18 22:11:19 -080046
Jayant Chowdhary249e1f22018-09-24 15:07:45 -070047static constexpr int kWindowHalTokenSizeMax = 256;
48
49static native_handle_t *convertHalTokenToNativeHandle(const HalToken &halToken);
50
Yin-Chia Yehc3603822016-01-18 22:11:19 -080051bool
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070052AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
53 // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
54 // AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN (0x6) is sufficient as it implies
55 // AHARDWAREBUFFER_USAGE_CPU_READ (0x2).
56 bool hasCpuUsage = usage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080057 switch (format) {
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080058 case AIMAGE_FORMAT_RGBA_8888:
59 case AIMAGE_FORMAT_RGBX_8888:
60 case AIMAGE_FORMAT_RGB_888:
61 case AIMAGE_FORMAT_RGB_565:
62 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080063 case AIMAGE_FORMAT_YUV_420_888:
64 case AIMAGE_FORMAT_JPEG:
65 case AIMAGE_FORMAT_RAW16:
Jayant Chowdhary5fa12762019-03-13 15:01:58 -070066 case AIMAGE_FORMAT_RAW_DEPTH:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080067 case AIMAGE_FORMAT_RAW_PRIVATE:
68 case AIMAGE_FORMAT_RAW10:
69 case AIMAGE_FORMAT_RAW12:
70 case AIMAGE_FORMAT_DEPTH16:
71 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
Shuzhen Wang1cfbbec2018-10-08 13:55:28 -070072 case AIMAGE_FORMAT_Y8:
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080073 case AIMAGE_FORMAT_HEIC:
Emilian Peev44df34d2019-02-12 09:30:15 -080074 case AIMAGE_FORMAT_DEPTH_JPEG:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080075 return true;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070076 case AIMAGE_FORMAT_PRIVATE:
77 // For private format, cpu usage is prohibited.
78 return !hasCpuUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080079 default:
80 return false;
81 }
82}
83
84int
85AImageReader::getNumPlanesForFormat(int32_t format) {
86 switch (format) {
87 case AIMAGE_FORMAT_YUV_420_888:
88 return 3;
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080089 case AIMAGE_FORMAT_RGBA_8888:
90 case AIMAGE_FORMAT_RGBX_8888:
91 case AIMAGE_FORMAT_RGB_888:
92 case AIMAGE_FORMAT_RGB_565:
93 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080094 case AIMAGE_FORMAT_JPEG:
95 case AIMAGE_FORMAT_RAW16:
Jayant Chowdhary5fa12762019-03-13 15:01:58 -070096 case AIMAGE_FORMAT_RAW_DEPTH:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080097 case AIMAGE_FORMAT_RAW_PRIVATE:
98 case AIMAGE_FORMAT_RAW10:
99 case AIMAGE_FORMAT_RAW12:
100 case AIMAGE_FORMAT_DEPTH16:
101 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
Shuzhen Wang1cfbbec2018-10-08 13:55:28 -0700102 case AIMAGE_FORMAT_Y8:
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800103 case AIMAGE_FORMAT_HEIC:
Emilian Peev44df34d2019-02-12 09:30:15 -0800104 case AIMAGE_FORMAT_DEPTH_JPEG:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800105 return 1;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700106 case AIMAGE_FORMAT_PRIVATE:
107 return 0;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800108 default:
109 return -1;
110 }
111}
112
113void
114AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800115 sp<AImageReader> reader = mReader.promote();
116 if (reader == nullptr) {
117 ALOGW("A frame is available after AImageReader closed!");
118 return; // reader has been closed
119 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700120 Mutex::Autolock _l(mLock);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800121 if (mListener.onImageAvailable == nullptr) {
122 return; // No callback registered
123 }
124
125 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
126 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
127 msg->setPointer(AImageReader::kContextKey, mListener.context);
128 msg->post();
129}
130
131media_status_t
132AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
133 Mutex::Autolock _l(mLock);
134 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700135 mListener.context = nullptr;
136 mListener.onImageAvailable = nullptr;
137 } else {
138 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800139 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800140 return AMEDIA_OK;
141}
142
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800143void
144AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800145 sp<AImageReader> reader = mReader.promote();
146 if (reader == nullptr) {
147 ALOGW("A frame is available after AImageReader closed!");
148 return; // reader has been closed
149 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700150 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800151 if (mListener.onBufferRemoved == nullptr) {
152 return; // No callback registered
153 }
154
155 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
156 if (gBuffer == nullptr) {
157 ALOGW("A buffer being freed has gone away!");
158 return; // buffer is already destroyed
159 }
160
161 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
162 msg->setPointer(
163 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
164 msg->setPointer(AImageReader::kContextKey, mListener.context);
165 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
166 msg->post();
167}
168
169media_status_t
170AImageReader::BufferRemovedListener::setBufferRemovedListener(
171 AImageReader_BufferRemovedListener* listener) {
172 Mutex::Autolock _l(mLock);
173 if (listener == nullptr) {
174 mListener.context = nullptr;
175 mListener.onBufferRemoved = nullptr;
176 } else {
177 mListener = *listener;
178 }
179 return AMEDIA_OK;
180}
181
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800182media_status_t
183AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
184 return mFrameListener->setImageListener(listener);
185}
186
187media_status_t
188AImageReader::setImageListener(AImageReader_ImageListener* listener) {
189 Mutex::Autolock _l(mLock);
190 return setImageListenerLocked(listener);
191}
192
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800193media_status_t
194AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
195 return mBufferRemovedListener->setBufferRemovedListener(listener);
196}
197
198media_status_t
199AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
200 Mutex::Autolock _l(mLock);
201 return setBufferRemovedListenerLocked(listener);
202}
203
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800204void AImageReader::CallbackHandler::onMessageReceived(
205 const sp<AMessage> &msg) {
206 switch (msg->what()) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800207 case kWhatBufferRemoved:
208 {
209 AImageReader_BufferRemovedCallback onBufferRemoved;
210 void* context;
211 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
212 if (!found || onBufferRemoved == nullptr) {
213 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
214 return;
215 }
216 found = msg->findPointer(kContextKey, &context);
217 if (!found) {
218 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
219 return;
220 }
221 sp<RefBase> bufferToFree;
222 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
223 if (!found || bufferToFree == nullptr) {
224 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
225 return;
226 }
227
228 // TODO(jwcai) Someone from Android graphics team stating this should just be a
229 // static_cast.
230 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
231
232 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
233 // this AImageReader, and the reference will be gone once this function returns.
234 (*onBufferRemoved)(context, mReader, outBuffer);
235 break;
236 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800237 case kWhatImageAvailable:
238 {
239 AImageReader_ImageCallback onImageAvailable;
240 void* context;
241 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
242 if (!found || onImageAvailable == nullptr) {
243 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
244 return;
245 }
246 found = msg->findPointer(kContextKey, &context);
247 if (!found) {
248 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
249 return;
250 }
251 (*onImageAvailable)(context, mReader);
252 break;
253 }
254 default:
255 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
256 break;
257 }
258}
259
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800260AImageReader::AImageReader(int32_t width,
261 int32_t height,
262 int32_t format,
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700263 uint64_t usage,
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800264 int32_t maxImages)
265 : mWidth(width),
266 mHeight(height),
267 mFormat(format),
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700268 mUsage(usage),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800269 mMaxImages(maxImages),
270 mNumPlanes(getNumPlanesForFormat(format)),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800271 mFrameListener(new FrameListener(this)),
272 mBufferRemovedListener(new BufferRemovedListener(this)) {}
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800273
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700274AImageReader::~AImageReader() {
275 Mutex::Autolock _l(mLock);
276 LOG_FATAL_IF("AImageReader not closed before destruction", mIsClosed != true);
277}
278
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800279media_status_t
280AImageReader::init() {
281 PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
Jooyung Han86cbf712019-02-21 15:25:02 +0900282 mHalFormat = mapPublicFormatToHalFormat(publicFormat);
283 mHalDataSpace = mapPublicFormatToHalDataspace(publicFormat);
Jooyung Han27d84b72019-02-21 15:12:59 +0900284 mHalUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800285
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800286 sp<IGraphicBufferProducer> gbProducer;
287 sp<IGraphicBufferConsumer> gbConsumer;
288 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
289
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700290 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
291 mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800292 createProcessUniqueId());
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800293
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800294 mBufferItemConsumer =
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800295 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800296 if (mBufferItemConsumer == nullptr) {
297 ALOGE("Failed to allocate BufferItemConsumer");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800298 return AMEDIA_ERROR_UNKNOWN;
299 }
300
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800301 mProducer = gbProducer;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800302 mBufferItemConsumer->setName(consumerName);
303 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800304 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800305
306 status_t res;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800307 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800308 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800309 ALOGE("Failed to set BufferItemConsumer buffer size");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800310 return AMEDIA_ERROR_UNKNOWN;
311 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800312 res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800313 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800314 ALOGE("Failed to set BufferItemConsumer buffer format");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800315 return AMEDIA_ERROR_UNKNOWN;
316 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800317 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800318 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800319 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800320 return AMEDIA_ERROR_UNKNOWN;
321 }
Khushalff20fd42019-01-22 15:31:00 -0800322 if (mUsage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
323 gbConsumer->setConsumerIsProtected(true);
324 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800325
326 mSurface = new Surface(mProducer, /*controlledByApp*/true);
327 if (mSurface == nullptr) {
328 ALOGE("Failed to create surface");
329 return AMEDIA_ERROR_UNKNOWN;
330 }
331 mWindow = static_cast<ANativeWindow*>(mSurface.get());
332
333 for (int i = 0; i < mMaxImages; i++) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800334 BufferItem* buffer = new BufferItem;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800335 mBuffers.push_back(buffer);
336 }
337
338 mCbLooper = new ALooper;
339 mCbLooper->setName(consumerName.string());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800340 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800341 /*runOnCallingThread*/false,
342 /*canCallJava*/ true,
343 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800344 if (res != OK) {
345 ALOGE("Failed to start the looper");
346 return AMEDIA_ERROR_UNKNOWN;
347 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800348 mHandler = new CallbackHandler(this);
349 mCbLooper->registerHandler(mHandler);
350
351 return AMEDIA_OK;
352}
353
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700354void AImageReader::close() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800355 Mutex::Autolock _l(mLock);
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700356 if (mIsClosed) {
357 return;
358 }
359 mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800360 AImageReader_ImageListener nullListener = {nullptr, nullptr};
361 setImageListenerLocked(&nullListener);
362
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800363 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
364 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
365
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800366 if (mCbLooper != nullptr) {
367 mCbLooper->unregisterHandler(mHandler->id());
368 mCbLooper->stop();
369 }
370 mCbLooper.clear();
371 mHandler.clear();
372
373 // Close all previously acquired images
374 for (auto it = mAcquiredImages.begin();
375 it != mAcquiredImages.end(); it++) {
376 AImage* image = *it;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800377 Mutex::Autolock _l(image->mLock);
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800378 // Do not alter mAcquiredImages while we are iterating on it
379 releaseImageLocked(image, /*releaseFenceFd*/-1, /*clearCache*/false);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800380 }
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800381 mAcquiredImages.clear();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800382
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800383 // Delete Buffer Items
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800384 for (auto it = mBuffers.begin();
385 it != mBuffers.end(); it++) {
386 delete *it;
387 }
388
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800389 if (mBufferItemConsumer != nullptr) {
390 mBufferItemConsumer->abandon();
391 mBufferItemConsumer->setFrameAvailableListener(nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800392 }
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700393
394 if (mWindowHandle != nullptr) {
395 int size = mWindowHandle->data[0];
396 hidl_vec<uint8_t> halToken;
397 halToken.setToExternal(
398 reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
399 deleteHalToken(halToken);
400 native_handle_delete(mWindowHandle);
401 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800402}
403
404media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800405AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800406 *image = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800407 BufferItem* buffer = getBufferItemLocked();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800408 if (buffer == nullptr) {
409 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
410 " maxImages buffers");
411 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
412 }
413
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800414 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
415 bool waitForFence = acquireFenceFd == nullptr;
416 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
417
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800418 if (res != NO_ERROR) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800419 returnBufferItemLocked(buffer);
420 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
421 if (res == INVALID_OPERATION) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800422 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
423 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800424 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
425 __FUNCTION__, strerror(-res), res);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800426 return AMEDIA_ERROR_UNKNOWN;
427 }
428 }
429 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
430 }
431
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800432 const int bufferWidth = getBufferWidth(buffer);
433 const int bufferHeight = getBufferHeight(buffer);
434 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800435 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800436
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800437 const int readerWidth = mWidth;
438 const int readerHeight = mHeight;
439 const int readerFmt = mHalFormat;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800440 const int readerUsage = mHalUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800441
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800442 // Check if the producer buffer configurations match what AImageReader configured. Add some
443 // extra checks for non-opaque formats.
444 if (!isFormatOpaque(readerFmt)) {
445 // Check if the left-top corner of the crop rect is origin, we currently assume this point
446 // is zero, will revisit this once this assumption turns out problematic.
447 Point lt = buffer->mCrop.leftTop();
448 if (lt.x != 0 || lt.y != 0) {
449 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800450 return AMEDIA_ERROR_UNKNOWN;
451 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800452
453 // Check if the producer buffer configurations match what ImageReader configured.
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -0700454 ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
455 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
456 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800457
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800458 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
459 // ImageReader requested has been supported from the producer side.
460 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
461 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
462 "configured: %x",
463 __FUNCTION__, bufferUsage, readerUsage);
464
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800465 if (readerFmt != bufferFmt) {
466 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
467 // Special casing for when producer switches to a format compatible with flexible
468 // YUV.
469 mHalFormat = bufferFmt;
470 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
471 } else {
472 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
473 // used anywhere yet.
474 mBufferItemConsumer->releaseBuffer(*buffer);
475 returnBufferItemLocked(buffer);
476
477 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
478 __FUNCTION__, bufferFmt, readerFmt);
479
480 return AMEDIA_ERROR_UNKNOWN;
481 }
482 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800483 }
484
485 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700486 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800487 readerWidth, readerHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800488 } else {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700489 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800490 bufferWidth, bufferHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800491 }
492 mAcquiredImages.push_back(*image);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800493
494 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
495 if (acquireFenceFd != nullptr) {
496 *acquireFenceFd = buffer->mFence->dup();
497 }
498
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800499 return AMEDIA_OK;
500}
501
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800502BufferItem*
503AImageReader::getBufferItemLocked() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800504 if (mBuffers.empty()) {
505 return nullptr;
506 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800507 // Return a BufferItem pointer and remove it from the list
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800508 auto it = mBuffers.begin();
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800509 BufferItem* buffer = *it;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800510 mBuffers.erase(it);
511 return buffer;
512}
513
514void
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800515AImageReader::returnBufferItemLocked(BufferItem* buffer) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800516 mBuffers.push_back(buffer);
517}
518
519void
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800520AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd, bool clearCache) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800521 BufferItem* buffer = image->mBuffer;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800522 if (buffer == nullptr) {
523 // This should not happen, but is not fatal
524 ALOGW("AImage %p has no buffer!", image);
525 return;
526 }
527
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800528 int unlockFenceFd = -1;
529 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800530 if (ret < 0) {
531 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
532 return;
533 }
534
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800535 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
536 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
537 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
538 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800539 returnBufferItemLocked(buffer);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800540 image->mBuffer = nullptr;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800541 image->mLockedBuffer = nullptr;
542 image->mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800543
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800544 if (!clearCache) {
545 return;
546 }
547
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800548 bool found = false;
549 // cleanup acquired image list
550 for (auto it = mAcquiredImages.begin();
551 it != mAcquiredImages.end(); it++) {
552 AImage* readerCopy = *it;
553 if (readerCopy == image) {
554 found = true;
555 mAcquiredImages.erase(it);
556 break;
557 }
558 }
559 if (!found) {
560 ALOGE("Error: AImage %p is not generated by AImageReader %p",
561 image, this);
562 }
563}
564
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700565media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
566 if (mWindowHandle != nullptr) {
567 *handle = mWindowHandle;
568 return AMEDIA_OK;
569 }
570 sp<HGraphicBufferProducer> hgbp =
571 new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
572 HalToken halToken;
573 if (!createHalToken(hgbp, &halToken)) {
574 return AMEDIA_ERROR_UNKNOWN;
575 }
576 mWindowHandle = convertHalTokenToNativeHandle(halToken);
577 if (!mWindowHandle) {
578 return AMEDIA_ERROR_UNKNOWN;
579 }
580 *handle = mWindowHandle;
581 return AMEDIA_OK;
582}
583
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800584int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800585AImageReader::getBufferWidth(BufferItem* buffer) {
586 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800587
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800588 if (!buffer->mCrop.isEmpty()) {
589 return buffer->mCrop.getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800590 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800591
592 return buffer->mGraphicBuffer->getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800593}
594
595int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800596AImageReader::getBufferHeight(BufferItem* buffer) {
597 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800598
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800599 if (!buffer->mCrop.isEmpty()) {
600 return buffer->mCrop.getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800601 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800602
603 return buffer->mGraphicBuffer->getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800604}
605
606media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800607AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800608 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800609 return acquireImageLocked(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800610}
611
612media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800613AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800614 if (image == nullptr) {
615 return AMEDIA_ERROR_INVALID_PARAMETER;
616 }
617 Mutex::Autolock _l(mLock);
618 *image = nullptr;
619 AImage* prevImage = nullptr;
620 AImage* nextImage = nullptr;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800621 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800622 if (prevImage == nullptr) {
623 return ret;
624 }
625 for (;;) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800626 ret = acquireImageLocked(&nextImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800627 if (nextImage == nullptr) {
628 *image = prevImage;
629 return AMEDIA_OK;
630 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800631
632 if (acquireFenceFd == nullptr) {
633 // No need for release fence here since the prevImage is unused and acquireImageLocked
634 // has already waited for acquired fence to be signaled.
635 prevImage->close();
636 } else {
637 // Use the acquire fence as release fence, so that producer can wait before trying to
638 // refill the buffer.
639 prevImage->close(*acquireFenceFd);
640 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800641 prevImage->free();
642 prevImage = nextImage;
643 nextImage = nullptr;
644 }
645}
646
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700647static native_handle_t *convertHalTokenToNativeHandle(
648 const HalToken &halToken) {
649 // We attempt to store halToken in the ints of the native_handle_t after its
650 // size. The first int stores the size of the token. We store this in an int
651 // to avoid alignment issues where size_t and int do not have the same
652 // alignment.
653 size_t nhDataByteSize = halToken.size();
654 if (nhDataByteSize > kWindowHalTokenSizeMax) {
655 // The size of the token isn't reasonable..
656 return nullptr;
657 }
658 size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
659
660 // We don't check for overflow, whether numInts can fit in an int, since we
661 // expect kWindowHalTokenSizeMax to be a reasonable limit.
662 // create a native_handle_t with 0 numFds and numInts number of ints.
663 native_handle_t *nh =
664 native_handle_create(0, numInts);
665 if (!nh) {
666 return nullptr;
667 }
668 // Store the size of the token in the first int.
669 nh->data[0] = nhDataByteSize;
670 memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
671 return nh;
672}
673
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800674EXPORT
675media_status_t AImageReader_new(
676 int32_t width, int32_t height, int32_t format, int32_t maxImages,
677 /*out*/AImageReader** reader) {
678 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800679 return AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700680 width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800681}
682
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700683extern "C" {
684
685EXPORT
686media_status_t AImageReader_getWindowNativeHandle(
687 AImageReader *reader, /*out*/native_handle_t **handle) {
688 if (reader == nullptr || handle == nullptr) {
689 return AMEDIA_ERROR_INVALID_PARAMETER;
690 }
691 return reader->getWindowNativeHandle(handle);
692}
693
694} //extern "C"
695
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800696EXPORT
697media_status_t AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700698 int32_t width, int32_t height, int32_t format, uint64_t usage,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800699 int32_t maxImages, /*out*/ AImageReader** reader) {
700 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800701
702 if (width < 1 || height < 1) {
703 ALOGE("%s: image dimension must be positive: w:%d h:%d",
704 __FUNCTION__, width, height);
705 return AMEDIA_ERROR_INVALID_PARAMETER;
706 }
707
708 if (maxImages < 1) {
709 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
710 __FUNCTION__, maxImages);
711 return AMEDIA_ERROR_INVALID_PARAMETER;
712 }
713
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800714 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
715 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
716 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
717 return AMEDIA_ERROR_INVALID_PARAMETER;
718 }
719
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700720 if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
721 ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
722 __FUNCTION__, format, usage);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800723 return AMEDIA_ERROR_INVALID_PARAMETER;
724 }
725
726 if (reader == nullptr) {
727 ALOGE("%s: reader argument is null", __FUNCTION__);
728 return AMEDIA_ERROR_INVALID_PARAMETER;
729 }
730
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800731 AImageReader* tmpReader = new AImageReader(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700732 width, height, format, usage, maxImages);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800733 if (tmpReader == nullptr) {
734 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
735 return AMEDIA_ERROR_UNKNOWN;
736 }
737 media_status_t ret = tmpReader->init();
738 if (ret != AMEDIA_OK) {
739 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
740 delete tmpReader;
741 return ret;
742 }
743 *reader = tmpReader;
744 (*reader)->incStrong((void*) AImageReader_new);
745 return AMEDIA_OK;
746}
747
748EXPORT
749void AImageReader_delete(AImageReader* reader) {
750 ALOGV("%s", __FUNCTION__);
751 if (reader != nullptr) {
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700752 reader->close();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800753 reader->decStrong((void*) AImageReader_delete);
754 }
755 return;
756}
757
758EXPORT
759media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
Yin-Chia Yehe2ded212017-11-08 15:51:02 -0800760 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800761 if (reader == nullptr || window == nullptr) {
762 ALOGE("%s: invalid argument. reader %p, window %p",
763 __FUNCTION__, reader, window);
764 return AMEDIA_ERROR_INVALID_PARAMETER;
765 }
766 *window = reader->getWindow();
767 return AMEDIA_OK;
768}
769
770EXPORT
771media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
772 ALOGV("%s", __FUNCTION__);
773 if (reader == nullptr || width == nullptr) {
774 ALOGE("%s: invalid argument. reader %p, width %p",
775 __FUNCTION__, reader, width);
776 return AMEDIA_ERROR_INVALID_PARAMETER;
777 }
778 *width = reader->getWidth();
779 return AMEDIA_OK;
780}
781
782EXPORT
783media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
784 ALOGV("%s", __FUNCTION__);
785 if (reader == nullptr || height == nullptr) {
786 ALOGE("%s: invalid argument. reader %p, height %p",
787 __FUNCTION__, reader, height);
788 return AMEDIA_ERROR_INVALID_PARAMETER;
789 }
790 *height = reader->getHeight();
791 return AMEDIA_OK;
792}
793
794EXPORT
795media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
796 ALOGV("%s", __FUNCTION__);
797 if (reader == nullptr || format == nullptr) {
798 ALOGE("%s: invalid argument. reader %p, format %p",
799 __FUNCTION__, reader, format);
800 return AMEDIA_ERROR_INVALID_PARAMETER;
801 }
802 *format = reader->getFormat();
803 return AMEDIA_OK;
804}
805
806EXPORT
807media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
808 ALOGV("%s", __FUNCTION__);
809 if (reader == nullptr || maxImages == nullptr) {
810 ALOGE("%s: invalid argument. reader %p, maxImages %p",
811 __FUNCTION__, reader, maxImages);
812 return AMEDIA_ERROR_INVALID_PARAMETER;
813 }
814 *maxImages = reader->getMaxImages();
815 return AMEDIA_OK;
816}
817
818EXPORT
819media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
820 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800821 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800822}
823
824EXPORT
825media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
826 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800827 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
828}
829
830EXPORT
831media_status_t AImageReader_acquireNextImageAsync(
832 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
833 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800834 if (reader == nullptr || image == nullptr) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800835 ALOGE("%s: invalid argument. reader %p, image %p",
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800836 __FUNCTION__, reader, image);
837 return AMEDIA_ERROR_INVALID_PARAMETER;
838 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800839 return reader->acquireNextImage(image, acquireFenceFd);
840}
841
842EXPORT
843media_status_t AImageReader_acquireLatestImageAsync(
844 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
845 ALOGV("%s", __FUNCTION__);
846 if (reader == nullptr || image == nullptr) {
847 ALOGE("%s: invalid argument. reader %p, image %p",
848 __FUNCTION__, reader, image);
849 return AMEDIA_ERROR_INVALID_PARAMETER;
850 }
851 return reader->acquireLatestImage(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800852}
853
854EXPORT
855media_status_t AImageReader_setImageListener(
856 AImageReader* reader, AImageReader_ImageListener* listener) {
857 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700858 if (reader == nullptr) {
859 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800860 return AMEDIA_ERROR_INVALID_PARAMETER;
861 }
862
863 reader->setImageListener(listener);
864 return AMEDIA_OK;
865}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800866
867EXPORT
868media_status_t AImageReader_setBufferRemovedListener(
869 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
870 ALOGV("%s", __FUNCTION__);
871 if (reader == nullptr) {
872 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
873 return AMEDIA_ERROR_INVALID_PARAMETER;
874 }
875
876 reader->setBufferRemovedListener(listener);
877 return AMEDIA_OK;
878}