blob: 92704995e0863e01eb510cf987d47805bfcdc208 [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 Yehf6e6a8e2021-04-08 11:49:42 -070075 case AIMAGE_FORMAT_RAW_DEPTH10:
Emilian Peevdded00c2022-09-27 14:20:41 -070076 case HAL_PIXEL_FORMAT_YCBCR_P010:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080077 return true;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070078 case AIMAGE_FORMAT_PRIVATE:
79 // For private format, cpu usage is prohibited.
80 return !hasCpuUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080081 default:
82 return false;
83 }
84}
85
86int
87AImageReader::getNumPlanesForFormat(int32_t format) {
88 switch (format) {
89 case AIMAGE_FORMAT_YUV_420_888:
Emilian Peevdded00c2022-09-27 14:20:41 -070090 case HAL_PIXEL_FORMAT_YCBCR_P010:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080091 return 3;
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080092 case AIMAGE_FORMAT_RGBA_8888:
93 case AIMAGE_FORMAT_RGBX_8888:
94 case AIMAGE_FORMAT_RGB_888:
95 case AIMAGE_FORMAT_RGB_565:
96 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080097 case AIMAGE_FORMAT_JPEG:
98 case AIMAGE_FORMAT_RAW16:
Jayant Chowdhary5fa12762019-03-13 15:01:58 -070099 case AIMAGE_FORMAT_RAW_DEPTH:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800100 case AIMAGE_FORMAT_RAW_PRIVATE:
101 case AIMAGE_FORMAT_RAW10:
102 case AIMAGE_FORMAT_RAW12:
103 case AIMAGE_FORMAT_DEPTH16:
104 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
Shuzhen Wang1cfbbec2018-10-08 13:55:28 -0700105 case AIMAGE_FORMAT_Y8:
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800106 case AIMAGE_FORMAT_HEIC:
Emilian Peev44df34d2019-02-12 09:30:15 -0800107 case AIMAGE_FORMAT_DEPTH_JPEG:
Yin-Chia Yehf6e6a8e2021-04-08 11:49:42 -0700108 case AIMAGE_FORMAT_RAW_DEPTH10:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800109 return 1;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700110 case AIMAGE_FORMAT_PRIVATE:
111 return 0;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800112 default:
113 return -1;
114 }
115}
116
117void
118AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800119 sp<AImageReader> reader = mReader.promote();
120 if (reader == nullptr) {
121 ALOGW("A frame is available after AImageReader closed!");
122 return; // reader has been closed
123 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700124 Mutex::Autolock _l(mLock);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800125 if (mListener.onImageAvailable == nullptr) {
126 return; // No callback registered
127 }
128
129 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
130 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
131 msg->setPointer(AImageReader::kContextKey, mListener.context);
132 msg->post();
133}
134
135media_status_t
136AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
137 Mutex::Autolock _l(mLock);
138 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700139 mListener.context = nullptr;
140 mListener.onImageAvailable = nullptr;
141 } else {
142 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800143 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800144 return AMEDIA_OK;
145}
146
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800147void
148AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800149 sp<AImageReader> reader = mReader.promote();
150 if (reader == nullptr) {
151 ALOGW("A frame is available after AImageReader closed!");
152 return; // reader has been closed
153 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700154 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800155 if (mListener.onBufferRemoved == nullptr) {
156 return; // No callback registered
157 }
158
159 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
160 if (gBuffer == nullptr) {
161 ALOGW("A buffer being freed has gone away!");
162 return; // buffer is already destroyed
163 }
164
165 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
166 msg->setPointer(
167 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
168 msg->setPointer(AImageReader::kContextKey, mListener.context);
169 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
170 msg->post();
171}
172
173media_status_t
174AImageReader::BufferRemovedListener::setBufferRemovedListener(
175 AImageReader_BufferRemovedListener* listener) {
176 Mutex::Autolock _l(mLock);
177 if (listener == nullptr) {
178 mListener.context = nullptr;
179 mListener.onBufferRemoved = nullptr;
180 } else {
181 mListener = *listener;
182 }
183 return AMEDIA_OK;
184}
185
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800186media_status_t
187AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
188 return mFrameListener->setImageListener(listener);
189}
190
191media_status_t
192AImageReader::setImageListener(AImageReader_ImageListener* listener) {
193 Mutex::Autolock _l(mLock);
194 return setImageListenerLocked(listener);
195}
196
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800197media_status_t
198AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
199 return mBufferRemovedListener->setBufferRemovedListener(listener);
200}
201
202media_status_t
203AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
204 Mutex::Autolock _l(mLock);
205 return setBufferRemovedListenerLocked(listener);
206}
207
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800208void AImageReader::CallbackHandler::onMessageReceived(
209 const sp<AMessage> &msg) {
210 switch (msg->what()) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800211 case kWhatBufferRemoved:
212 {
213 AImageReader_BufferRemovedCallback onBufferRemoved;
214 void* context;
215 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
216 if (!found || onBufferRemoved == nullptr) {
217 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
218 return;
219 }
220 found = msg->findPointer(kContextKey, &context);
221 if (!found) {
222 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
223 return;
224 }
225 sp<RefBase> bufferToFree;
226 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
227 if (!found || bufferToFree == nullptr) {
228 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
229 return;
230 }
231
232 // TODO(jwcai) Someone from Android graphics team stating this should just be a
233 // static_cast.
234 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
235
236 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
237 // this AImageReader, and the reference will be gone once this function returns.
238 (*onBufferRemoved)(context, mReader, outBuffer);
239 break;
240 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800241 case kWhatImageAvailable:
242 {
243 AImageReader_ImageCallback onImageAvailable;
244 void* context;
245 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
246 if (!found || onImageAvailable == nullptr) {
247 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
248 return;
249 }
250 found = msg->findPointer(kContextKey, &context);
251 if (!found) {
252 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
253 return;
254 }
255 (*onImageAvailable)(context, mReader);
256 break;
257 }
258 default:
259 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
260 break;
261 }
262}
263
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800264AImageReader::AImageReader(int32_t width,
265 int32_t height,
266 int32_t format,
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700267 uint64_t usage,
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800268 int32_t maxImages)
269 : mWidth(width),
270 mHeight(height),
271 mFormat(format),
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700272 mUsage(usage),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800273 mMaxImages(maxImages),
274 mNumPlanes(getNumPlanesForFormat(format)),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800275 mFrameListener(new FrameListener(this)),
276 mBufferRemovedListener(new BufferRemovedListener(this)) {}
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800277
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700278AImageReader::~AImageReader() {
279 Mutex::Autolock _l(mLock);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800280 LOG_FATAL_IF(mIsOpen, "AImageReader not closed before destruction");
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700281}
282
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800283media_status_t
284AImageReader::init() {
285 PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
Jooyung Han86cbf712019-02-21 15:25:02 +0900286 mHalFormat = mapPublicFormatToHalFormat(publicFormat);
287 mHalDataSpace = mapPublicFormatToHalDataspace(publicFormat);
Jooyung Han27d84b72019-02-21 15:12:59 +0900288 mHalUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800289
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800290 sp<IGraphicBufferProducer> gbProducer;
291 sp<IGraphicBufferConsumer> gbConsumer;
292 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
293
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700294 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
295 mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800296 createProcessUniqueId());
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800297
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800298 mBufferItemConsumer =
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800299 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800300 if (mBufferItemConsumer == nullptr) {
301 ALOGE("Failed to allocate BufferItemConsumer");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800302 return AMEDIA_ERROR_UNKNOWN;
303 }
304
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800305 mProducer = gbProducer;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800306 mBufferItemConsumer->setName(consumerName);
307 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800308 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800309
310 status_t res;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800311 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800312 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800313 ALOGE("Failed to set BufferItemConsumer buffer size");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800314 return AMEDIA_ERROR_UNKNOWN;
315 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800316 res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800317 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800318 ALOGE("Failed to set BufferItemConsumer buffer format");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800319 return AMEDIA_ERROR_UNKNOWN;
320 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800321 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800322 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800323 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800324 return AMEDIA_ERROR_UNKNOWN;
325 }
Khushalff20fd42019-01-22 15:31:00 -0800326 if (mUsage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
327 gbConsumer->setConsumerIsProtected(true);
328 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800329
330 mSurface = new Surface(mProducer, /*controlledByApp*/true);
331 if (mSurface == nullptr) {
332 ALOGE("Failed to create surface");
333 return AMEDIA_ERROR_UNKNOWN;
334 }
335 mWindow = static_cast<ANativeWindow*>(mSurface.get());
336
337 for (int i = 0; i < mMaxImages; i++) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800338 BufferItem* buffer = new BufferItem;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800339 mBuffers.push_back(buffer);
340 }
341
342 mCbLooper = new ALooper;
343 mCbLooper->setName(consumerName.string());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800344 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800345 /*runOnCallingThread*/false,
346 /*canCallJava*/ true,
347 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800348 if (res != OK) {
349 ALOGE("Failed to start the looper");
350 return AMEDIA_ERROR_UNKNOWN;
351 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800352 mHandler = new CallbackHandler(this);
353 mCbLooper->registerHandler(mHandler);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800354 mIsOpen = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800355 return AMEDIA_OK;
356}
357
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700358void AImageReader::close() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800359 Mutex::Autolock _l(mLock);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800360 if (!mIsOpen) {
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700361 return;
362 }
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800363 mIsOpen = false;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800364 AImageReader_ImageListener nullListener = {nullptr, nullptr};
365 setImageListenerLocked(&nullListener);
366
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800367 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
368 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
369
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800370 if (mCbLooper != nullptr) {
371 mCbLooper->unregisterHandler(mHandler->id());
372 mCbLooper->stop();
373 }
374 mCbLooper.clear();
375 mHandler.clear();
376
377 // Close all previously acquired images
378 for (auto it = mAcquiredImages.begin();
379 it != mAcquiredImages.end(); it++) {
380 AImage* image = *it;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800381 Mutex::Autolock _l(image->mLock);
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800382 // Do not alter mAcquiredImages while we are iterating on it
383 releaseImageLocked(image, /*releaseFenceFd*/-1, /*clearCache*/false);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800384 }
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800385 mAcquiredImages.clear();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800386
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800387 // Delete Buffer Items
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800388 for (auto it = mBuffers.begin();
389 it != mBuffers.end(); it++) {
390 delete *it;
391 }
392
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800393 if (mBufferItemConsumer != nullptr) {
394 mBufferItemConsumer->abandon();
395 mBufferItemConsumer->setFrameAvailableListener(nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800396 }
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700397
398 if (mWindowHandle != nullptr) {
399 int size = mWindowHandle->data[0];
400 hidl_vec<uint8_t> halToken;
401 halToken.setToExternal(
402 reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
403 deleteHalToken(halToken);
404 native_handle_delete(mWindowHandle);
405 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800406}
407
408media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800409AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800410 *image = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800411 BufferItem* buffer = getBufferItemLocked();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800412 if (buffer == nullptr) {
413 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
414 " maxImages buffers");
415 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
416 }
417
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800418 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
419 bool waitForFence = acquireFenceFd == nullptr;
420 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
421
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800422 if (res != NO_ERROR) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800423 returnBufferItemLocked(buffer);
424 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
425 if (res == INVALID_OPERATION) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800426 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
427 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800428 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
429 __FUNCTION__, strerror(-res), res);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800430 return AMEDIA_ERROR_UNKNOWN;
431 }
432 }
433 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
434 }
435
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800436 const int bufferWidth = getBufferWidth(buffer);
437 const int bufferHeight = getBufferHeight(buffer);
438 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800439 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800440
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800441 const int readerWidth = mWidth;
442 const int readerHeight = mHeight;
443 const int readerFmt = mHalFormat;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800444 const int readerUsage = mHalUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800445
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800446 // Check if the producer buffer configurations match what AImageReader configured. Add some
447 // extra checks for non-opaque formats.
448 if (!isFormatOpaque(readerFmt)) {
449 // Check if the left-top corner of the crop rect is origin, we currently assume this point
450 // is zero, will revisit this once this assumption turns out problematic.
451 Point lt = buffer->mCrop.leftTop();
452 if (lt.x != 0 || lt.y != 0) {
453 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800454 return AMEDIA_ERROR_UNKNOWN;
455 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800456
457 // Check if the producer buffer configurations match what ImageReader configured.
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -0700458 ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
459 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
460 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800461
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800462 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
463 // ImageReader requested has been supported from the producer side.
464 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
465 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
466 "configured: %x",
467 __FUNCTION__, bufferUsage, readerUsage);
468
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800469 if (readerFmt != bufferFmt) {
470 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
471 // Special casing for when producer switches to a format compatible with flexible
472 // YUV.
473 mHalFormat = bufferFmt;
474 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
475 } else {
476 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
477 // used anywhere yet.
478 mBufferItemConsumer->releaseBuffer(*buffer);
479 returnBufferItemLocked(buffer);
480
481 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
482 __FUNCTION__, bufferFmt, readerFmt);
483
484 return AMEDIA_ERROR_UNKNOWN;
485 }
486 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800487 }
488
489 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
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 readerWidth, readerHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800492 } else {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700493 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800494 bufferWidth, bufferHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800495 }
496 mAcquiredImages.push_back(*image);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800497
498 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
499 if (acquireFenceFd != nullptr) {
500 *acquireFenceFd = buffer->mFence->dup();
501 }
502
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800503 return AMEDIA_OK;
504}
505
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800506BufferItem*
507AImageReader::getBufferItemLocked() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800508 if (mBuffers.empty()) {
509 return nullptr;
510 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800511 // Return a BufferItem pointer and remove it from the list
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800512 auto it = mBuffers.begin();
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800513 BufferItem* buffer = *it;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800514 mBuffers.erase(it);
515 return buffer;
516}
517
518void
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800519AImageReader::returnBufferItemLocked(BufferItem* buffer) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800520 mBuffers.push_back(buffer);
521}
522
523void
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800524AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd, bool clearCache) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800525 BufferItem* buffer = image->mBuffer;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800526 if (buffer == nullptr) {
527 // This should not happen, but is not fatal
528 ALOGW("AImage %p has no buffer!", image);
529 return;
530 }
531
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800532 int unlockFenceFd = -1;
533 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800534 if (ret < 0) {
535 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
536 return;
537 }
538
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800539 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
540 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
541 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
542 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800543 returnBufferItemLocked(buffer);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800544 image->mBuffer = nullptr;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800545 image->mLockedBuffer = nullptr;
546 image->mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800547
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800548 if (!clearCache) {
549 return;
550 }
551
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800552 bool found = false;
553 // cleanup acquired image list
554 for (auto it = mAcquiredImages.begin();
555 it != mAcquiredImages.end(); it++) {
556 AImage* readerCopy = *it;
557 if (readerCopy == image) {
558 found = true;
559 mAcquiredImages.erase(it);
560 break;
561 }
562 }
563 if (!found) {
564 ALOGE("Error: AImage %p is not generated by AImageReader %p",
565 image, this);
566 }
567}
568
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700569media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
570 if (mWindowHandle != nullptr) {
571 *handle = mWindowHandle;
572 return AMEDIA_OK;
573 }
574 sp<HGraphicBufferProducer> hgbp =
575 new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
576 HalToken halToken;
577 if (!createHalToken(hgbp, &halToken)) {
578 return AMEDIA_ERROR_UNKNOWN;
579 }
580 mWindowHandle = convertHalTokenToNativeHandle(halToken);
581 if (!mWindowHandle) {
582 return AMEDIA_ERROR_UNKNOWN;
583 }
584 *handle = mWindowHandle;
585 return AMEDIA_OK;
586}
587
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800588int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800589AImageReader::getBufferWidth(BufferItem* buffer) {
590 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800591
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800592 if (!buffer->mCrop.isEmpty()) {
593 return buffer->mCrop.getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800594 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800595
596 return buffer->mGraphicBuffer->getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800597}
598
599int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800600AImageReader::getBufferHeight(BufferItem* buffer) {
601 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800602
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800603 if (!buffer->mCrop.isEmpty()) {
604 return buffer->mCrop.getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800605 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800606
607 return buffer->mGraphicBuffer->getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800608}
609
610media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800611AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800612 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800613 return acquireImageLocked(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800614}
615
616media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800617AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800618 if (image == nullptr) {
619 return AMEDIA_ERROR_INVALID_PARAMETER;
620 }
621 Mutex::Autolock _l(mLock);
622 *image = nullptr;
623 AImage* prevImage = nullptr;
624 AImage* nextImage = nullptr;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800625 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800626 if (prevImage == nullptr) {
627 return ret;
628 }
629 for (;;) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800630 ret = acquireImageLocked(&nextImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800631 if (nextImage == nullptr) {
632 *image = prevImage;
633 return AMEDIA_OK;
634 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800635
636 if (acquireFenceFd == nullptr) {
637 // No need for release fence here since the prevImage is unused and acquireImageLocked
638 // has already waited for acquired fence to be signaled.
639 prevImage->close();
640 } else {
641 // Use the acquire fence as release fence, so that producer can wait before trying to
642 // refill the buffer.
643 prevImage->close(*acquireFenceFd);
644 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800645 prevImage->free();
646 prevImage = nextImage;
647 nextImage = nullptr;
648 }
649}
650
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700651static native_handle_t *convertHalTokenToNativeHandle(
652 const HalToken &halToken) {
653 // We attempt to store halToken in the ints of the native_handle_t after its
654 // size. The first int stores the size of the token. We store this in an int
655 // to avoid alignment issues where size_t and int do not have the same
656 // alignment.
657 size_t nhDataByteSize = halToken.size();
658 if (nhDataByteSize > kWindowHalTokenSizeMax) {
659 // The size of the token isn't reasonable..
660 return nullptr;
661 }
662 size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
663
664 // We don't check for overflow, whether numInts can fit in an int, since we
665 // expect kWindowHalTokenSizeMax to be a reasonable limit.
666 // create a native_handle_t with 0 numFds and numInts number of ints.
667 native_handle_t *nh =
668 native_handle_create(0, numInts);
669 if (!nh) {
670 return nullptr;
671 }
672 // Store the size of the token in the first int.
673 nh->data[0] = nhDataByteSize;
674 memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
675 return nh;
676}
677
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800678EXPORT
679media_status_t AImageReader_new(
680 int32_t width, int32_t height, int32_t format, int32_t maxImages,
681 /*out*/AImageReader** reader) {
682 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800683 return AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700684 width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800685}
686
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700687extern "C" {
688
689EXPORT
690media_status_t AImageReader_getWindowNativeHandle(
691 AImageReader *reader, /*out*/native_handle_t **handle) {
692 if (reader == nullptr || handle == nullptr) {
693 return AMEDIA_ERROR_INVALID_PARAMETER;
694 }
695 return reader->getWindowNativeHandle(handle);
696}
697
698} //extern "C"
699
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800700EXPORT
701media_status_t AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700702 int32_t width, int32_t height, int32_t format, uint64_t usage,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800703 int32_t maxImages, /*out*/ AImageReader** reader) {
704 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800705
706 if (width < 1 || height < 1) {
707 ALOGE("%s: image dimension must be positive: w:%d h:%d",
708 __FUNCTION__, width, height);
709 return AMEDIA_ERROR_INVALID_PARAMETER;
710 }
711
712 if (maxImages < 1) {
713 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
714 __FUNCTION__, maxImages);
715 return AMEDIA_ERROR_INVALID_PARAMETER;
716 }
717
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800718 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
719 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
720 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
721 return AMEDIA_ERROR_INVALID_PARAMETER;
722 }
723
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700724 if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
725 ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
726 __FUNCTION__, format, usage);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800727 return AMEDIA_ERROR_INVALID_PARAMETER;
728 }
729
730 if (reader == nullptr) {
731 ALOGE("%s: reader argument is null", __FUNCTION__);
732 return AMEDIA_ERROR_INVALID_PARAMETER;
733 }
734
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800735 AImageReader* tmpReader = new AImageReader(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700736 width, height, format, usage, maxImages);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800737 if (tmpReader == nullptr) {
738 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
739 return AMEDIA_ERROR_UNKNOWN;
740 }
741 media_status_t ret = tmpReader->init();
742 if (ret != AMEDIA_OK) {
743 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
744 delete tmpReader;
745 return ret;
746 }
747 *reader = tmpReader;
748 (*reader)->incStrong((void*) AImageReader_new);
749 return AMEDIA_OK;
750}
751
752EXPORT
753void AImageReader_delete(AImageReader* reader) {
754 ALOGV("%s", __FUNCTION__);
755 if (reader != nullptr) {
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700756 reader->close();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800757 reader->decStrong((void*) AImageReader_delete);
758 }
759 return;
760}
761
762EXPORT
763media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
Yin-Chia Yehe2ded212017-11-08 15:51:02 -0800764 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800765 if (reader == nullptr || window == nullptr) {
766 ALOGE("%s: invalid argument. reader %p, window %p",
767 __FUNCTION__, reader, window);
768 return AMEDIA_ERROR_INVALID_PARAMETER;
769 }
770 *window = reader->getWindow();
771 return AMEDIA_OK;
772}
773
774EXPORT
775media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
776 ALOGV("%s", __FUNCTION__);
777 if (reader == nullptr || width == nullptr) {
778 ALOGE("%s: invalid argument. reader %p, width %p",
779 __FUNCTION__, reader, width);
780 return AMEDIA_ERROR_INVALID_PARAMETER;
781 }
782 *width = reader->getWidth();
783 return AMEDIA_OK;
784}
785
786EXPORT
787media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
788 ALOGV("%s", __FUNCTION__);
789 if (reader == nullptr || height == nullptr) {
790 ALOGE("%s: invalid argument. reader %p, height %p",
791 __FUNCTION__, reader, height);
792 return AMEDIA_ERROR_INVALID_PARAMETER;
793 }
794 *height = reader->getHeight();
795 return AMEDIA_OK;
796}
797
798EXPORT
799media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
800 ALOGV("%s", __FUNCTION__);
801 if (reader == nullptr || format == nullptr) {
802 ALOGE("%s: invalid argument. reader %p, format %p",
803 __FUNCTION__, reader, format);
804 return AMEDIA_ERROR_INVALID_PARAMETER;
805 }
806 *format = reader->getFormat();
807 return AMEDIA_OK;
808}
809
810EXPORT
811media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
812 ALOGV("%s", __FUNCTION__);
813 if (reader == nullptr || maxImages == nullptr) {
814 ALOGE("%s: invalid argument. reader %p, maxImages %p",
815 __FUNCTION__, reader, maxImages);
816 return AMEDIA_ERROR_INVALID_PARAMETER;
817 }
818 *maxImages = reader->getMaxImages();
819 return AMEDIA_OK;
820}
821
822EXPORT
823media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
824 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800825 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800826}
827
828EXPORT
829media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
830 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800831 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
832}
833
834EXPORT
835media_status_t AImageReader_acquireNextImageAsync(
836 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
837 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800838 if (reader == nullptr || image == nullptr) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800839 ALOGE("%s: invalid argument. reader %p, image %p",
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800840 __FUNCTION__, reader, image);
841 return AMEDIA_ERROR_INVALID_PARAMETER;
842 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800843 return reader->acquireNextImage(image, acquireFenceFd);
844}
845
846EXPORT
847media_status_t AImageReader_acquireLatestImageAsync(
848 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
849 ALOGV("%s", __FUNCTION__);
850 if (reader == nullptr || image == nullptr) {
851 ALOGE("%s: invalid argument. reader %p, image %p",
852 __FUNCTION__, reader, image);
853 return AMEDIA_ERROR_INVALID_PARAMETER;
854 }
855 return reader->acquireLatestImage(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800856}
857
858EXPORT
859media_status_t AImageReader_setImageListener(
860 AImageReader* reader, AImageReader_ImageListener* listener) {
861 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700862 if (reader == nullptr) {
863 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800864 return AMEDIA_ERROR_INVALID_PARAMETER;
865 }
866
867 reader->setImageListener(listener);
868 return AMEDIA_OK;
869}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800870
871EXPORT
872media_status_t AImageReader_setBufferRemovedListener(
873 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
874 ALOGV("%s", __FUNCTION__);
875 if (reader == nullptr) {
876 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
877 return AMEDIA_ERROR_INVALID_PARAMETER;
878 }
879
880 reader->setBufferRemovedListener(listener);
881 return AMEDIA_OK;
882}