blob: 7b19ac01f2274a93bb5dbb51eb5cc01e4840cafa [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
Sally Qida6ca842022-01-10 16:10:28 -080049static media_status_t validateParameters(int32_t width, int32_t height, int32_t format,
50 uint64_t usage, int32_t maxImages,
51 /*out*/ AImageReader**& reader);
Jayant Chowdhary249e1f22018-09-24 15:07:45 -070052static native_handle_t *convertHalTokenToNativeHandle(const HalToken &halToken);
53
Yin-Chia Yehc3603822016-01-18 22:11:19 -080054bool
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070055AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
56 // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
57 // AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN (0x6) is sufficient as it implies
58 // AHARDWAREBUFFER_USAGE_CPU_READ (0x2).
59 bool hasCpuUsage = usage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080060 switch (format) {
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080061 case AIMAGE_FORMAT_RGBA_8888:
62 case AIMAGE_FORMAT_RGBX_8888:
63 case AIMAGE_FORMAT_RGB_888:
64 case AIMAGE_FORMAT_RGB_565:
65 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080066 case AIMAGE_FORMAT_YUV_420_888:
67 case AIMAGE_FORMAT_JPEG:
68 case AIMAGE_FORMAT_RAW16:
Jayant Chowdhary5fa12762019-03-13 15:01:58 -070069 case AIMAGE_FORMAT_RAW_DEPTH:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080070 case AIMAGE_FORMAT_RAW_PRIVATE:
71 case AIMAGE_FORMAT_RAW10:
72 case AIMAGE_FORMAT_RAW12:
73 case AIMAGE_FORMAT_DEPTH16:
74 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
Shuzhen Wang1cfbbec2018-10-08 13:55:28 -070075 case AIMAGE_FORMAT_Y8:
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -080076 case AIMAGE_FORMAT_HEIC:
Emilian Peev44df34d2019-02-12 09:30:15 -080077 case AIMAGE_FORMAT_DEPTH_JPEG:
Yin-Chia Yehf6e6a8e2021-04-08 11:49:42 -070078 case AIMAGE_FORMAT_RAW_DEPTH10:
Emilian Peevdded00c2022-09-27 14:20:41 -070079 case HAL_PIXEL_FORMAT_YCBCR_P010:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080080 return true;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070081 case AIMAGE_FORMAT_PRIVATE:
82 // For private format, cpu usage is prohibited.
83 return !hasCpuUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080084 default:
85 return false;
86 }
87}
88
89int
90AImageReader::getNumPlanesForFormat(int32_t format) {
91 switch (format) {
92 case AIMAGE_FORMAT_YUV_420_888:
Emilian Peevdded00c2022-09-27 14:20:41 -070093 case HAL_PIXEL_FORMAT_YCBCR_P010:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080094 return 3;
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080095 case AIMAGE_FORMAT_RGBA_8888:
96 case AIMAGE_FORMAT_RGBX_8888:
97 case AIMAGE_FORMAT_RGB_888:
98 case AIMAGE_FORMAT_RGB_565:
99 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800100 case AIMAGE_FORMAT_JPEG:
101 case AIMAGE_FORMAT_RAW16:
Jayant Chowdhary5fa12762019-03-13 15:01:58 -0700102 case AIMAGE_FORMAT_RAW_DEPTH:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800103 case AIMAGE_FORMAT_RAW_PRIVATE:
104 case AIMAGE_FORMAT_RAW10:
105 case AIMAGE_FORMAT_RAW12:
106 case AIMAGE_FORMAT_DEPTH16:
107 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
Shuzhen Wang1cfbbec2018-10-08 13:55:28 -0700108 case AIMAGE_FORMAT_Y8:
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800109 case AIMAGE_FORMAT_HEIC:
Emilian Peev44df34d2019-02-12 09:30:15 -0800110 case AIMAGE_FORMAT_DEPTH_JPEG:
Yin-Chia Yehf6e6a8e2021-04-08 11:49:42 -0700111 case AIMAGE_FORMAT_RAW_DEPTH10:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800112 return 1;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700113 case AIMAGE_FORMAT_PRIVATE:
114 return 0;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800115 default:
116 return -1;
117 }
118}
119
120void
121AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800122 sp<AImageReader> reader = mReader.promote();
123 if (reader == nullptr) {
124 ALOGW("A frame is available after AImageReader closed!");
125 return; // reader has been closed
126 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700127 Mutex::Autolock _l(mLock);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800128 if (mListener.onImageAvailable == nullptr) {
129 return; // No callback registered
130 }
131
132 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
133 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
134 msg->setPointer(AImageReader::kContextKey, mListener.context);
135 msg->post();
136}
137
138media_status_t
139AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
140 Mutex::Autolock _l(mLock);
141 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700142 mListener.context = nullptr;
143 mListener.onImageAvailable = nullptr;
144 } else {
145 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800146 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800147 return AMEDIA_OK;
148}
149
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800150void
151AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800152 sp<AImageReader> reader = mReader.promote();
153 if (reader == nullptr) {
154 ALOGW("A frame is available after AImageReader closed!");
155 return; // reader has been closed
156 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700157 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800158 if (mListener.onBufferRemoved == nullptr) {
159 return; // No callback registered
160 }
161
162 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
163 if (gBuffer == nullptr) {
164 ALOGW("A buffer being freed has gone away!");
165 return; // buffer is already destroyed
166 }
167
168 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
169 msg->setPointer(
170 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
171 msg->setPointer(AImageReader::kContextKey, mListener.context);
172 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
173 msg->post();
174}
175
176media_status_t
177AImageReader::BufferRemovedListener::setBufferRemovedListener(
178 AImageReader_BufferRemovedListener* listener) {
179 Mutex::Autolock _l(mLock);
180 if (listener == nullptr) {
181 mListener.context = nullptr;
182 mListener.onBufferRemoved = nullptr;
183 } else {
184 mListener = *listener;
185 }
186 return AMEDIA_OK;
187}
188
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800189media_status_t
190AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
191 return mFrameListener->setImageListener(listener);
192}
193
194media_status_t
195AImageReader::setImageListener(AImageReader_ImageListener* listener) {
196 Mutex::Autolock _l(mLock);
197 return setImageListenerLocked(listener);
198}
199
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800200media_status_t
201AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
202 return mBufferRemovedListener->setBufferRemovedListener(listener);
203}
204
205media_status_t
206AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
207 Mutex::Autolock _l(mLock);
208 return setBufferRemovedListenerLocked(listener);
209}
210
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800211void AImageReader::CallbackHandler::onMessageReceived(
212 const sp<AMessage> &msg) {
213 switch (msg->what()) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800214 case kWhatBufferRemoved:
215 {
216 AImageReader_BufferRemovedCallback onBufferRemoved;
217 void* context;
218 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
219 if (!found || onBufferRemoved == nullptr) {
220 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
221 return;
222 }
223 found = msg->findPointer(kContextKey, &context);
224 if (!found) {
225 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
226 return;
227 }
228 sp<RefBase> bufferToFree;
229 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
230 if (!found || bufferToFree == nullptr) {
231 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
232 return;
233 }
234
235 // TODO(jwcai) Someone from Android graphics team stating this should just be a
236 // static_cast.
237 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
238
239 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
240 // this AImageReader, and the reference will be gone once this function returns.
241 (*onBufferRemoved)(context, mReader, outBuffer);
242 break;
243 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800244 case kWhatImageAvailable:
245 {
246 AImageReader_ImageCallback onImageAvailable;
247 void* context;
248 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
249 if (!found || onImageAvailable == nullptr) {
250 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
251 return;
252 }
253 found = msg->findPointer(kContextKey, &context);
254 if (!found) {
255 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
256 return;
257 }
258 (*onImageAvailable)(context, mReader);
259 break;
260 }
261 default:
262 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
263 break;
264 }
265}
266
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800267AImageReader::AImageReader(int32_t width,
268 int32_t height,
269 int32_t format,
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700270 uint64_t usage,
Sally Qida6ca842022-01-10 16:10:28 -0800271 int32_t maxImages,
272 uint32_t hardwareBufferFormat,
273 android_dataspace dataSpace)
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800274 : mWidth(width),
275 mHeight(height),
276 mFormat(format),
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700277 mUsage(usage),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800278 mMaxImages(maxImages),
279 mNumPlanes(getNumPlanesForFormat(format)),
Sally Qida6ca842022-01-10 16:10:28 -0800280 mHalFormat(hardwareBufferFormat),
281 mHalDataSpace(dataSpace),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800282 mFrameListener(new FrameListener(this)),
283 mBufferRemovedListener(new BufferRemovedListener(this)) {}
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800284
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700285AImageReader::~AImageReader() {
286 Mutex::Autolock _l(mLock);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800287 LOG_FATAL_IF(mIsOpen, "AImageReader not closed before destruction");
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700288}
289
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800290media_status_t
291AImageReader::init() {
Jooyung Han27d84b72019-02-21 15:12:59 +0900292 mHalUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800293
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800294 sp<IGraphicBufferProducer> gbProducer;
295 sp<IGraphicBufferConsumer> gbConsumer;
296 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
297
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700298 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
299 mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800300 createProcessUniqueId());
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800301
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800302 mBufferItemConsumer =
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800303 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800304 if (mBufferItemConsumer == nullptr) {
305 ALOGE("Failed to allocate BufferItemConsumer");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800306 return AMEDIA_ERROR_UNKNOWN;
307 }
308
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800309 mProducer = gbProducer;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800310 mBufferItemConsumer->setName(consumerName);
311 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800312 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800313
314 status_t res;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800315 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800316 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800317 ALOGE("Failed to set BufferItemConsumer buffer size");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800318 return AMEDIA_ERROR_UNKNOWN;
319 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800320 res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800321 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800322 ALOGE("Failed to set BufferItemConsumer buffer format");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800323 return AMEDIA_ERROR_UNKNOWN;
324 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800325 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800326 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800327 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800328 return AMEDIA_ERROR_UNKNOWN;
329 }
Khushalff20fd42019-01-22 15:31:00 -0800330 if (mUsage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
331 gbConsumer->setConsumerIsProtected(true);
332 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800333
334 mSurface = new Surface(mProducer, /*controlledByApp*/true);
335 if (mSurface == nullptr) {
336 ALOGE("Failed to create surface");
337 return AMEDIA_ERROR_UNKNOWN;
338 }
339 mWindow = static_cast<ANativeWindow*>(mSurface.get());
340
341 for (int i = 0; i < mMaxImages; i++) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800342 BufferItem* buffer = new BufferItem;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800343 mBuffers.push_back(buffer);
344 }
345
346 mCbLooper = new ALooper;
Tomasz Wasilczyk90623d12023-08-15 20:59:35 +0000347 mCbLooper->setName(consumerName.c_str());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800348 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800349 /*runOnCallingThread*/false,
350 /*canCallJava*/ true,
351 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800352 if (res != OK) {
353 ALOGE("Failed to start the looper");
354 return AMEDIA_ERROR_UNKNOWN;
355 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800356 mHandler = new CallbackHandler(this);
357 mCbLooper->registerHandler(mHandler);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800358 mIsOpen = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800359 return AMEDIA_OK;
360}
361
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700362void AImageReader::close() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800363 Mutex::Autolock _l(mLock);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800364 if (!mIsOpen) {
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700365 return;
366 }
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800367 mIsOpen = false;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800368 AImageReader_ImageListener nullListener = {nullptr, nullptr};
369 setImageListenerLocked(&nullListener);
370
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800371 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
372 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
373
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800374 if (mCbLooper != nullptr) {
375 mCbLooper->unregisterHandler(mHandler->id());
376 mCbLooper->stop();
377 }
378 mCbLooper.clear();
379 mHandler.clear();
380
381 // Close all previously acquired images
382 for (auto it = mAcquiredImages.begin();
383 it != mAcquiredImages.end(); it++) {
384 AImage* image = *it;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800385 Mutex::Autolock _l(image->mLock);
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800386 // Do not alter mAcquiredImages while we are iterating on it
387 releaseImageLocked(image, /*releaseFenceFd*/-1, /*clearCache*/false);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800388 }
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800389 mAcquiredImages.clear();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800390
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800391 // Delete Buffer Items
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800392 for (auto it = mBuffers.begin();
393 it != mBuffers.end(); it++) {
394 delete *it;
395 }
396
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800397 if (mBufferItemConsumer != nullptr) {
398 mBufferItemConsumer->abandon();
399 mBufferItemConsumer->setFrameAvailableListener(nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800400 }
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700401
402 if (mWindowHandle != nullptr) {
403 int size = mWindowHandle->data[0];
404 hidl_vec<uint8_t> halToken;
405 halToken.setToExternal(
406 reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
407 deleteHalToken(halToken);
408 native_handle_delete(mWindowHandle);
409 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800410}
411
412media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800413AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800414 *image = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800415 BufferItem* buffer = getBufferItemLocked();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800416 if (buffer == nullptr) {
417 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
418 " maxImages buffers");
419 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
420 }
421
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800422 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
423 bool waitForFence = acquireFenceFd == nullptr;
424 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
425
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800426 if (res != NO_ERROR) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800427 returnBufferItemLocked(buffer);
428 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
429 if (res == INVALID_OPERATION) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800430 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
431 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800432 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
433 __FUNCTION__, strerror(-res), res);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800434 return AMEDIA_ERROR_UNKNOWN;
435 }
436 }
437 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
438 }
439
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800440 const int bufferWidth = getBufferWidth(buffer);
441 const int bufferHeight = getBufferHeight(buffer);
442 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800443 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800444
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800445 const int readerWidth = mWidth;
446 const int readerHeight = mHeight;
447 const int readerFmt = mHalFormat;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800448 const int readerUsage = mHalUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800449
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800450 // Check if the producer buffer configurations match what AImageReader configured. Add some
451 // extra checks for non-opaque formats.
452 if (!isFormatOpaque(readerFmt)) {
453 // Check if the left-top corner of the crop rect is origin, we currently assume this point
454 // is zero, will revisit this once this assumption turns out problematic.
455 Point lt = buffer->mCrop.leftTop();
456 if (lt.x != 0 || lt.y != 0) {
457 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800458 return AMEDIA_ERROR_UNKNOWN;
459 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800460
461 // Check if the producer buffer configurations match what ImageReader configured.
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -0700462 ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
463 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
464 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800465
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800466 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
467 // ImageReader requested has been supported from the producer side.
468 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
469 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
470 "configured: %x",
471 __FUNCTION__, bufferUsage, readerUsage);
472
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800473 if (readerFmt != bufferFmt) {
474 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
475 // Special casing for when producer switches to a format compatible with flexible
476 // YUV.
477 mHalFormat = bufferFmt;
478 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
479 } else {
480 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
481 // used anywhere yet.
482 mBufferItemConsumer->releaseBuffer(*buffer);
483 returnBufferItemLocked(buffer);
484
485 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
486 __FUNCTION__, bufferFmt, readerFmt);
487
488 return AMEDIA_ERROR_UNKNOWN;
489 }
490 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800491 }
492
493 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700494 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800495 readerWidth, readerHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800496 } else {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700497 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800498 bufferWidth, bufferHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800499 }
500 mAcquiredImages.push_back(*image);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800501
502 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
503 if (acquireFenceFd != nullptr) {
504 *acquireFenceFd = buffer->mFence->dup();
505 }
506
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800507 return AMEDIA_OK;
508}
509
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800510BufferItem*
511AImageReader::getBufferItemLocked() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800512 if (mBuffers.empty()) {
513 return nullptr;
514 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800515 // Return a BufferItem pointer and remove it from the list
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800516 auto it = mBuffers.begin();
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800517 BufferItem* buffer = *it;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800518 mBuffers.erase(it);
519 return buffer;
520}
521
522void
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800523AImageReader::returnBufferItemLocked(BufferItem* buffer) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800524 mBuffers.push_back(buffer);
525}
526
527void
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800528AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd, bool clearCache) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800529 BufferItem* buffer = image->mBuffer;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800530 if (buffer == nullptr) {
531 // This should not happen, but is not fatal
532 ALOGW("AImage %p has no buffer!", image);
533 return;
534 }
535
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800536 int unlockFenceFd = -1;
537 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800538 if (ret < 0) {
539 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
540 return;
541 }
542
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800543 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
544 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
545 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
546 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800547 returnBufferItemLocked(buffer);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800548 image->mBuffer = nullptr;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800549 image->mLockedBuffer = nullptr;
550 image->mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800551
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800552 if (!clearCache) {
553 return;
554 }
555
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800556 bool found = false;
557 // cleanup acquired image list
558 for (auto it = mAcquiredImages.begin();
559 it != mAcquiredImages.end(); it++) {
560 AImage* readerCopy = *it;
561 if (readerCopy == image) {
562 found = true;
563 mAcquiredImages.erase(it);
564 break;
565 }
566 }
567 if (!found) {
568 ALOGE("Error: AImage %p is not generated by AImageReader %p",
569 image, this);
570 }
571}
572
Devin Moore5f866622023-06-05 22:25:40 +0000573// The LL-NDK API is now deprecated. New devices will no longer have the token
574// manager service installed, so createHalToken will return false and this
575// will return AMEDIA_ERROR_UNKNOWN on those devices.
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700576media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
577 if (mWindowHandle != nullptr) {
578 *handle = mWindowHandle;
579 return AMEDIA_OK;
580 }
581 sp<HGraphicBufferProducer> hgbp =
582 new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
583 HalToken halToken;
584 if (!createHalToken(hgbp, &halToken)) {
585 return AMEDIA_ERROR_UNKNOWN;
586 }
587 mWindowHandle = convertHalTokenToNativeHandle(halToken);
588 if (!mWindowHandle) {
589 return AMEDIA_ERROR_UNKNOWN;
590 }
591 *handle = mWindowHandle;
592 return AMEDIA_OK;
593}
594
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800595int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800596AImageReader::getBufferWidth(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.getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800601 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800602
603 return buffer->mGraphicBuffer->getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800604}
605
606int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800607AImageReader::getBufferHeight(BufferItem* buffer) {
608 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800609
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800610 if (!buffer->mCrop.isEmpty()) {
611 return buffer->mCrop.getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800612 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800613
614 return buffer->mGraphicBuffer->getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800615}
616
617media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800618AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800619 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800620 return acquireImageLocked(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800621}
622
623media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800624AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800625 if (image == nullptr) {
626 return AMEDIA_ERROR_INVALID_PARAMETER;
627 }
628 Mutex::Autolock _l(mLock);
629 *image = nullptr;
630 AImage* prevImage = nullptr;
631 AImage* nextImage = nullptr;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800632 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800633 if (prevImage == nullptr) {
634 return ret;
635 }
636 for (;;) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800637 ret = acquireImageLocked(&nextImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800638 if (nextImage == nullptr) {
639 *image = prevImage;
640 return AMEDIA_OK;
641 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800642
643 if (acquireFenceFd == nullptr) {
644 // No need for release fence here since the prevImage is unused and acquireImageLocked
645 // has already waited for acquired fence to be signaled.
646 prevImage->close();
647 } else {
648 // Use the acquire fence as release fence, so that producer can wait before trying to
649 // refill the buffer.
650 prevImage->close(*acquireFenceFd);
651 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800652 prevImage->free();
653 prevImage = nextImage;
654 nextImage = nullptr;
655 }
656}
657
Sally Qida6ca842022-01-10 16:10:28 -0800658static
659media_status_t validateParameters(int32_t width, int32_t height, int32_t format,
660 uint64_t usage, int32_t maxImages,
661 /*out*/ AImageReader**& reader) {
662 if (reader == nullptr) {
663 ALOGE("%s: reader argument is null", __FUNCTION__);
664 return AMEDIA_ERROR_INVALID_PARAMETER;
665 }
666
667 if (width < 1 || height < 1) {
668 ALOGE("%s: image dimension must be positive: w:%d h:%d",
669 __FUNCTION__, width, height);
670 return AMEDIA_ERROR_INVALID_PARAMETER;
671 }
672
673 if (maxImages < 1) {
674 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
675 __FUNCTION__, maxImages);
676 return AMEDIA_ERROR_INVALID_PARAMETER;
677 }
678
679 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
680 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
681 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
682 return AMEDIA_ERROR_INVALID_PARAMETER;
683 }
684
685 if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
686 ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
687 __FUNCTION__, format, usage);
688 return AMEDIA_ERROR_INVALID_PARAMETER;
689 }
690 return AMEDIA_OK;
691}
692
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700693static native_handle_t *convertHalTokenToNativeHandle(
694 const HalToken &halToken) {
695 // We attempt to store halToken in the ints of the native_handle_t after its
696 // size. The first int stores the size of the token. We store this in an int
697 // to avoid alignment issues where size_t and int do not have the same
698 // alignment.
699 size_t nhDataByteSize = halToken.size();
700 if (nhDataByteSize > kWindowHalTokenSizeMax) {
701 // The size of the token isn't reasonable..
702 return nullptr;
703 }
704 size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
705
706 // We don't check for overflow, whether numInts can fit in an int, since we
707 // expect kWindowHalTokenSizeMax to be a reasonable limit.
708 // create a native_handle_t with 0 numFds and numInts number of ints.
709 native_handle_t *nh =
710 native_handle_create(0, numInts);
711 if (!nh) {
712 return nullptr;
713 }
714 // Store the size of the token in the first int.
715 nh->data[0] = nhDataByteSize;
716 memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
717 return nh;
718}
719
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800720EXPORT
721media_status_t AImageReader_new(
722 int32_t width, int32_t height, int32_t format, int32_t maxImages,
723 /*out*/AImageReader** reader) {
724 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800725 return AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700726 width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800727}
728
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700729extern "C" {
730
731EXPORT
732media_status_t AImageReader_getWindowNativeHandle(
733 AImageReader *reader, /*out*/native_handle_t **handle) {
734 if (reader == nullptr || handle == nullptr) {
735 return AMEDIA_ERROR_INVALID_PARAMETER;
736 }
737 return reader->getWindowNativeHandle(handle);
738}
739
740} //extern "C"
741
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800742EXPORT
Sally Qida6ca842022-01-10 16:10:28 -0800743media_status_t AImageReader_newWithDataSpace(
744 int32_t width, int32_t height, uint64_t usage, int32_t maxImages,
745 uint32_t hardwareBufferFormat, int32_t dataSpace,
746 /*out*/ AImageReader** reader) {
747 ALOGV("%s", __FUNCTION__);
748
749 android_dataspace halDataSpace = static_cast<android_dataspace>(dataSpace);
750 int32_t format = static_cast<int32_t>(
751 mapHalFormatDataspaceToPublicFormat(hardwareBufferFormat, halDataSpace));
752 return AImageReader_newWithUsage(width, height, format, usage, maxImages, reader);
753}
754
755EXPORT
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800756media_status_t AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700757 int32_t width, int32_t height, int32_t format, uint64_t usage,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800758 int32_t maxImages, /*out*/ AImageReader** reader) {
759 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800760
Sally Qida6ca842022-01-10 16:10:28 -0800761 validateParameters(width, height, format, usage, maxImages, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800762
Sally Qida6ca842022-01-10 16:10:28 -0800763 PublicFormat publicFormat = static_cast<PublicFormat>(format);
764 uint32_t halFormat = mapPublicFormatToHalFormat(publicFormat);
765 android_dataspace halDataSpace = mapPublicFormatToHalDataspace(publicFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800766
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800767 AImageReader* tmpReader = new AImageReader(
Sally Qida6ca842022-01-10 16:10:28 -0800768 width, height, format, usage, maxImages, halFormat, halDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800769 if (tmpReader == nullptr) {
770 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
771 return AMEDIA_ERROR_UNKNOWN;
772 }
773 media_status_t ret = tmpReader->init();
774 if (ret != AMEDIA_OK) {
775 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
776 delete tmpReader;
777 return ret;
778 }
779 *reader = tmpReader;
780 (*reader)->incStrong((void*) AImageReader_new);
781 return AMEDIA_OK;
782}
783
784EXPORT
785void AImageReader_delete(AImageReader* reader) {
786 ALOGV("%s", __FUNCTION__);
787 if (reader != nullptr) {
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700788 reader->close();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800789 reader->decStrong((void*) AImageReader_delete);
790 }
791 return;
792}
793
794EXPORT
795media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
Yin-Chia Yehe2ded212017-11-08 15:51:02 -0800796 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800797 if (reader == nullptr || window == nullptr) {
798 ALOGE("%s: invalid argument. reader %p, window %p",
799 __FUNCTION__, reader, window);
800 return AMEDIA_ERROR_INVALID_PARAMETER;
801 }
802 *window = reader->getWindow();
803 return AMEDIA_OK;
804}
805
806EXPORT
807media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
808 ALOGV("%s", __FUNCTION__);
809 if (reader == nullptr || width == nullptr) {
810 ALOGE("%s: invalid argument. reader %p, width %p",
811 __FUNCTION__, reader, width);
812 return AMEDIA_ERROR_INVALID_PARAMETER;
813 }
814 *width = reader->getWidth();
815 return AMEDIA_OK;
816}
817
818EXPORT
819media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
820 ALOGV("%s", __FUNCTION__);
821 if (reader == nullptr || height == nullptr) {
822 ALOGE("%s: invalid argument. reader %p, height %p",
823 __FUNCTION__, reader, height);
824 return AMEDIA_ERROR_INVALID_PARAMETER;
825 }
826 *height = reader->getHeight();
827 return AMEDIA_OK;
828}
829
830EXPORT
831media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
832 ALOGV("%s", __FUNCTION__);
833 if (reader == nullptr || format == nullptr) {
834 ALOGE("%s: invalid argument. reader %p, format %p",
835 __FUNCTION__, reader, format);
836 return AMEDIA_ERROR_INVALID_PARAMETER;
837 }
838 *format = reader->getFormat();
839 return AMEDIA_OK;
840}
841
842EXPORT
843media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
844 ALOGV("%s", __FUNCTION__);
845 if (reader == nullptr || maxImages == nullptr) {
846 ALOGE("%s: invalid argument. reader %p, maxImages %p",
847 __FUNCTION__, reader, maxImages);
848 return AMEDIA_ERROR_INVALID_PARAMETER;
849 }
850 *maxImages = reader->getMaxImages();
851 return AMEDIA_OK;
852}
853
854EXPORT
855media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
856 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800857 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800858}
859
860EXPORT
861media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
862 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800863 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
864}
865
866EXPORT
867media_status_t AImageReader_acquireNextImageAsync(
868 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
869 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800870 if (reader == nullptr || image == nullptr) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800871 ALOGE("%s: invalid argument. reader %p, image %p",
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800872 __FUNCTION__, reader, image);
873 return AMEDIA_ERROR_INVALID_PARAMETER;
874 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800875 return reader->acquireNextImage(image, acquireFenceFd);
876}
877
878EXPORT
879media_status_t AImageReader_acquireLatestImageAsync(
880 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
881 ALOGV("%s", __FUNCTION__);
882 if (reader == nullptr || image == nullptr) {
883 ALOGE("%s: invalid argument. reader %p, image %p",
884 __FUNCTION__, reader, image);
885 return AMEDIA_ERROR_INVALID_PARAMETER;
886 }
887 return reader->acquireLatestImage(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800888}
889
890EXPORT
891media_status_t AImageReader_setImageListener(
892 AImageReader* reader, AImageReader_ImageListener* listener) {
893 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700894 if (reader == nullptr) {
895 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800896 return AMEDIA_ERROR_INVALID_PARAMETER;
897 }
898
899 reader->setImageListener(listener);
900 return AMEDIA_OK;
901}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800902
903EXPORT
904media_status_t AImageReader_setBufferRemovedListener(
905 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
906 ALOGV("%s", __FUNCTION__);
907 if (reader == nullptr) {
908 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
909 return AMEDIA_ERROR_INVALID_PARAMETER;
910 }
911
912 reader->setBufferRemovedListener(listener);
913 return AMEDIA_OK;
914}