blob: ac5cba84f7909cccf2c774d61a5da4be5d935b86 [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:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080079 return true;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070080 case AIMAGE_FORMAT_PRIVATE:
81 // For private format, cpu usage is prohibited.
82 return !hasCpuUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080083 default:
84 return false;
85 }
86}
87
88int
89AImageReader::getNumPlanesForFormat(int32_t format) {
90 switch (format) {
91 case AIMAGE_FORMAT_YUV_420_888:
92 return 3;
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080093 case AIMAGE_FORMAT_RGBA_8888:
94 case AIMAGE_FORMAT_RGBX_8888:
95 case AIMAGE_FORMAT_RGB_888:
96 case AIMAGE_FORMAT_RGB_565:
97 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080098 case AIMAGE_FORMAT_JPEG:
99 case AIMAGE_FORMAT_RAW16:
Jayant Chowdhary5fa12762019-03-13 15:01:58 -0700100 case AIMAGE_FORMAT_RAW_DEPTH:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800101 case AIMAGE_FORMAT_RAW_PRIVATE:
102 case AIMAGE_FORMAT_RAW10:
103 case AIMAGE_FORMAT_RAW12:
104 case AIMAGE_FORMAT_DEPTH16:
105 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
Shuzhen Wang1cfbbec2018-10-08 13:55:28 -0700106 case AIMAGE_FORMAT_Y8:
Shuzhen Wang68ac7ad2019-01-30 14:03:28 -0800107 case AIMAGE_FORMAT_HEIC:
Emilian Peev44df34d2019-02-12 09:30:15 -0800108 case AIMAGE_FORMAT_DEPTH_JPEG:
Yin-Chia Yehf6e6a8e2021-04-08 11:49:42 -0700109 case AIMAGE_FORMAT_RAW_DEPTH10:
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800110 return 1;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700111 case AIMAGE_FORMAT_PRIVATE:
112 return 0;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800113 default:
114 return -1;
115 }
116}
117
118void
119AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800120 sp<AImageReader> reader = mReader.promote();
121 if (reader == nullptr) {
122 ALOGW("A frame is available after AImageReader closed!");
123 return; // reader has been closed
124 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700125 Mutex::Autolock _l(mLock);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800126 if (mListener.onImageAvailable == nullptr) {
127 return; // No callback registered
128 }
129
130 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
131 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
132 msg->setPointer(AImageReader::kContextKey, mListener.context);
133 msg->post();
134}
135
136media_status_t
137AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
138 Mutex::Autolock _l(mLock);
139 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700140 mListener.context = nullptr;
141 mListener.onImageAvailable = nullptr;
142 } else {
143 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800144 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800145 return AMEDIA_OK;
146}
147
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800148void
149AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800150 sp<AImageReader> reader = mReader.promote();
151 if (reader == nullptr) {
152 ALOGW("A frame is available after AImageReader closed!");
153 return; // reader has been closed
154 }
Jayant Chowdharyebca5b92019-07-01 13:18:17 -0700155 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800156 if (mListener.onBufferRemoved == nullptr) {
157 return; // No callback registered
158 }
159
160 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
161 if (gBuffer == nullptr) {
162 ALOGW("A buffer being freed has gone away!");
163 return; // buffer is already destroyed
164 }
165
166 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
167 msg->setPointer(
168 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
169 msg->setPointer(AImageReader::kContextKey, mListener.context);
170 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
171 msg->post();
172}
173
174media_status_t
175AImageReader::BufferRemovedListener::setBufferRemovedListener(
176 AImageReader_BufferRemovedListener* listener) {
177 Mutex::Autolock _l(mLock);
178 if (listener == nullptr) {
179 mListener.context = nullptr;
180 mListener.onBufferRemoved = nullptr;
181 } else {
182 mListener = *listener;
183 }
184 return AMEDIA_OK;
185}
186
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800187media_status_t
188AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
189 return mFrameListener->setImageListener(listener);
190}
191
192media_status_t
193AImageReader::setImageListener(AImageReader_ImageListener* listener) {
194 Mutex::Autolock _l(mLock);
195 return setImageListenerLocked(listener);
196}
197
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800198media_status_t
199AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
200 return mBufferRemovedListener->setBufferRemovedListener(listener);
201}
202
203media_status_t
204AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
205 Mutex::Autolock _l(mLock);
206 return setBufferRemovedListenerLocked(listener);
207}
208
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800209void AImageReader::CallbackHandler::onMessageReceived(
210 const sp<AMessage> &msg) {
211 switch (msg->what()) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800212 case kWhatBufferRemoved:
213 {
214 AImageReader_BufferRemovedCallback onBufferRemoved;
215 void* context;
216 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
217 if (!found || onBufferRemoved == nullptr) {
218 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
219 return;
220 }
221 found = msg->findPointer(kContextKey, &context);
222 if (!found) {
223 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
224 return;
225 }
226 sp<RefBase> bufferToFree;
227 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
228 if (!found || bufferToFree == nullptr) {
229 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
230 return;
231 }
232
233 // TODO(jwcai) Someone from Android graphics team stating this should just be a
234 // static_cast.
235 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
236
237 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
238 // this AImageReader, and the reference will be gone once this function returns.
239 (*onBufferRemoved)(context, mReader, outBuffer);
240 break;
241 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800242 case kWhatImageAvailable:
243 {
244 AImageReader_ImageCallback onImageAvailable;
245 void* context;
246 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
247 if (!found || onImageAvailable == nullptr) {
248 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
249 return;
250 }
251 found = msg->findPointer(kContextKey, &context);
252 if (!found) {
253 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
254 return;
255 }
256 (*onImageAvailable)(context, mReader);
257 break;
258 }
259 default:
260 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
261 break;
262 }
263}
264
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800265AImageReader::AImageReader(int32_t width,
266 int32_t height,
267 int32_t format,
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700268 uint64_t usage,
Sally Qida6ca842022-01-10 16:10:28 -0800269 int32_t maxImages,
270 uint32_t hardwareBufferFormat,
271 android_dataspace dataSpace)
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800272 : mWidth(width),
273 mHeight(height),
274 mFormat(format),
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700275 mUsage(usage),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800276 mMaxImages(maxImages),
277 mNumPlanes(getNumPlanesForFormat(format)),
Sally Qida6ca842022-01-10 16:10:28 -0800278 mHalFormat(hardwareBufferFormat),
279 mHalDataSpace(dataSpace),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800280 mFrameListener(new FrameListener(this)),
281 mBufferRemovedListener(new BufferRemovedListener(this)) {}
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800282
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700283AImageReader::~AImageReader() {
284 Mutex::Autolock _l(mLock);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800285 LOG_FATAL_IF(mIsOpen, "AImageReader not closed before destruction");
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700286}
287
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800288media_status_t
289AImageReader::init() {
Jooyung Han27d84b72019-02-21 15:12:59 +0900290 mHalUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800291
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800292 sp<IGraphicBufferProducer> gbProducer;
293 sp<IGraphicBufferConsumer> gbConsumer;
294 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
295
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700296 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
297 mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800298 createProcessUniqueId());
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800299
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800300 mBufferItemConsumer =
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800301 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800302 if (mBufferItemConsumer == nullptr) {
303 ALOGE("Failed to allocate BufferItemConsumer");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800304 return AMEDIA_ERROR_UNKNOWN;
305 }
306
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800307 mProducer = gbProducer;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800308 mBufferItemConsumer->setName(consumerName);
309 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800310 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800311
312 status_t res;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800313 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800314 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800315 ALOGE("Failed to set BufferItemConsumer buffer size");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800316 return AMEDIA_ERROR_UNKNOWN;
317 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800318 res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800319 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800320 ALOGE("Failed to set BufferItemConsumer buffer format");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800321 return AMEDIA_ERROR_UNKNOWN;
322 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800323 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800324 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800325 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800326 return AMEDIA_ERROR_UNKNOWN;
327 }
Khushalff20fd42019-01-22 15:31:00 -0800328 if (mUsage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
329 gbConsumer->setConsumerIsProtected(true);
330 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800331
332 mSurface = new Surface(mProducer, /*controlledByApp*/true);
333 if (mSurface == nullptr) {
334 ALOGE("Failed to create surface");
335 return AMEDIA_ERROR_UNKNOWN;
336 }
337 mWindow = static_cast<ANativeWindow*>(mSurface.get());
338
339 for (int i = 0; i < mMaxImages; i++) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800340 BufferItem* buffer = new BufferItem;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800341 mBuffers.push_back(buffer);
342 }
343
344 mCbLooper = new ALooper;
345 mCbLooper->setName(consumerName.string());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800346 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800347 /*runOnCallingThread*/false,
348 /*canCallJava*/ true,
349 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800350 if (res != OK) {
351 ALOGE("Failed to start the looper");
352 return AMEDIA_ERROR_UNKNOWN;
353 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800354 mHandler = new CallbackHandler(this);
355 mCbLooper->registerHandler(mHandler);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800356 mIsOpen = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800357 return AMEDIA_OK;
358}
359
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700360void AImageReader::close() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800361 Mutex::Autolock _l(mLock);
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800362 if (!mIsOpen) {
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700363 return;
364 }
Jayant Chowdhary3a4af232020-12-15 11:01:03 -0800365 mIsOpen = false;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800366 AImageReader_ImageListener nullListener = {nullptr, nullptr};
367 setImageListenerLocked(&nullListener);
368
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800369 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
370 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
371
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800372 if (mCbLooper != nullptr) {
373 mCbLooper->unregisterHandler(mHandler->id());
374 mCbLooper->stop();
375 }
376 mCbLooper.clear();
377 mHandler.clear();
378
379 // Close all previously acquired images
380 for (auto it = mAcquiredImages.begin();
381 it != mAcquiredImages.end(); it++) {
382 AImage* image = *it;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800383 Mutex::Autolock _l(image->mLock);
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800384 // Do not alter mAcquiredImages while we are iterating on it
385 releaseImageLocked(image, /*releaseFenceFd*/-1, /*clearCache*/false);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800386 }
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800387 mAcquiredImages.clear();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800388
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800389 // Delete Buffer Items
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800390 for (auto it = mBuffers.begin();
391 it != mBuffers.end(); it++) {
392 delete *it;
393 }
394
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800395 if (mBufferItemConsumer != nullptr) {
396 mBufferItemConsumer->abandon();
397 mBufferItemConsumer->setFrameAvailableListener(nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800398 }
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700399
400 if (mWindowHandle != nullptr) {
401 int size = mWindowHandle->data[0];
402 hidl_vec<uint8_t> halToken;
403 halToken.setToExternal(
404 reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
405 deleteHalToken(halToken);
406 native_handle_delete(mWindowHandle);
407 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800408}
409
410media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800411AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800412 *image = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800413 BufferItem* buffer = getBufferItemLocked();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800414 if (buffer == nullptr) {
415 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
416 " maxImages buffers");
417 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
418 }
419
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800420 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
421 bool waitForFence = acquireFenceFd == nullptr;
422 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
423
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800424 if (res != NO_ERROR) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800425 returnBufferItemLocked(buffer);
426 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
427 if (res == INVALID_OPERATION) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800428 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
429 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800430 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
431 __FUNCTION__, strerror(-res), res);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800432 return AMEDIA_ERROR_UNKNOWN;
433 }
434 }
435 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
436 }
437
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800438 const int bufferWidth = getBufferWidth(buffer);
439 const int bufferHeight = getBufferHeight(buffer);
440 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800441 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800442
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800443 const int readerWidth = mWidth;
444 const int readerHeight = mHeight;
445 const int readerFmt = mHalFormat;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800446 const int readerUsage = mHalUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800447
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800448 // Check if the producer buffer configurations match what AImageReader configured. Add some
449 // extra checks for non-opaque formats.
450 if (!isFormatOpaque(readerFmt)) {
451 // Check if the left-top corner of the crop rect is origin, we currently assume this point
452 // is zero, will revisit this once this assumption turns out problematic.
453 Point lt = buffer->mCrop.leftTop();
454 if (lt.x != 0 || lt.y != 0) {
455 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800456 return AMEDIA_ERROR_UNKNOWN;
457 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800458
459 // Check if the producer buffer configurations match what ImageReader configured.
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -0700460 ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
461 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
462 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800463
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800464 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
465 // ImageReader requested has been supported from the producer side.
466 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
467 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
468 "configured: %x",
469 __FUNCTION__, bufferUsage, readerUsage);
470
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800471 if (readerFmt != bufferFmt) {
472 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
473 // Special casing for when producer switches to a format compatible with flexible
474 // YUV.
475 mHalFormat = bufferFmt;
476 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
477 } else {
478 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
479 // used anywhere yet.
480 mBufferItemConsumer->releaseBuffer(*buffer);
481 returnBufferItemLocked(buffer);
482
483 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
484 __FUNCTION__, bufferFmt, readerFmt);
485
486 return AMEDIA_ERROR_UNKNOWN;
487 }
488 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800489 }
490
491 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700492 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800493 readerWidth, readerHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800494 } else {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700495 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800496 bufferWidth, bufferHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800497 }
498 mAcquiredImages.push_back(*image);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800499
500 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
501 if (acquireFenceFd != nullptr) {
502 *acquireFenceFd = buffer->mFence->dup();
503 }
504
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800505 return AMEDIA_OK;
506}
507
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800508BufferItem*
509AImageReader::getBufferItemLocked() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800510 if (mBuffers.empty()) {
511 return nullptr;
512 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800513 // Return a BufferItem pointer and remove it from the list
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800514 auto it = mBuffers.begin();
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800515 BufferItem* buffer = *it;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800516 mBuffers.erase(it);
517 return buffer;
518}
519
520void
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800521AImageReader::returnBufferItemLocked(BufferItem* buffer) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800522 mBuffers.push_back(buffer);
523}
524
525void
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800526AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd, bool clearCache) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800527 BufferItem* buffer = image->mBuffer;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800528 if (buffer == nullptr) {
529 // This should not happen, but is not fatal
530 ALOGW("AImage %p has no buffer!", image);
531 return;
532 }
533
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800534 int unlockFenceFd = -1;
535 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800536 if (ret < 0) {
537 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
538 return;
539 }
540
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800541 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
542 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
543 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
544 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800545 returnBufferItemLocked(buffer);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800546 image->mBuffer = nullptr;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800547 image->mLockedBuffer = nullptr;
548 image->mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800549
Yin-Chia Yeh55baca22019-01-07 13:54:13 -0800550 if (!clearCache) {
551 return;
552 }
553
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800554 bool found = false;
555 // cleanup acquired image list
556 for (auto it = mAcquiredImages.begin();
557 it != mAcquiredImages.end(); it++) {
558 AImage* readerCopy = *it;
559 if (readerCopy == image) {
560 found = true;
561 mAcquiredImages.erase(it);
562 break;
563 }
564 }
565 if (!found) {
566 ALOGE("Error: AImage %p is not generated by AImageReader %p",
567 image, this);
568 }
569}
570
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700571media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
572 if (mWindowHandle != nullptr) {
573 *handle = mWindowHandle;
574 return AMEDIA_OK;
575 }
576 sp<HGraphicBufferProducer> hgbp =
577 new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
578 HalToken halToken;
579 if (!createHalToken(hgbp, &halToken)) {
580 return AMEDIA_ERROR_UNKNOWN;
581 }
582 mWindowHandle = convertHalTokenToNativeHandle(halToken);
583 if (!mWindowHandle) {
584 return AMEDIA_ERROR_UNKNOWN;
585 }
586 *handle = mWindowHandle;
587 return AMEDIA_OK;
588}
589
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800590int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800591AImageReader::getBufferWidth(BufferItem* buffer) {
592 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800593
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800594 if (!buffer->mCrop.isEmpty()) {
595 return buffer->mCrop.getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800596 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800597
598 return buffer->mGraphicBuffer->getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800599}
600
601int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800602AImageReader::getBufferHeight(BufferItem* buffer) {
603 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800604
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800605 if (!buffer->mCrop.isEmpty()) {
606 return buffer->mCrop.getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800607 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800608
609 return buffer->mGraphicBuffer->getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800610}
611
612media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800613AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800614 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800615 return acquireImageLocked(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800616}
617
618media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800619AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800620 if (image == nullptr) {
621 return AMEDIA_ERROR_INVALID_PARAMETER;
622 }
623 Mutex::Autolock _l(mLock);
624 *image = nullptr;
625 AImage* prevImage = nullptr;
626 AImage* nextImage = nullptr;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800627 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800628 if (prevImage == nullptr) {
629 return ret;
630 }
631 for (;;) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800632 ret = acquireImageLocked(&nextImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800633 if (nextImage == nullptr) {
634 *image = prevImage;
635 return AMEDIA_OK;
636 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800637
638 if (acquireFenceFd == nullptr) {
639 // No need for release fence here since the prevImage is unused and acquireImageLocked
640 // has already waited for acquired fence to be signaled.
641 prevImage->close();
642 } else {
643 // Use the acquire fence as release fence, so that producer can wait before trying to
644 // refill the buffer.
645 prevImage->close(*acquireFenceFd);
646 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800647 prevImage->free();
648 prevImage = nextImage;
649 nextImage = nullptr;
650 }
651}
652
Sally Qida6ca842022-01-10 16:10:28 -0800653static
654media_status_t validateParameters(int32_t width, int32_t height, int32_t format,
655 uint64_t usage, int32_t maxImages,
656 /*out*/ AImageReader**& reader) {
657 if (reader == nullptr) {
658 ALOGE("%s: reader argument is null", __FUNCTION__);
659 return AMEDIA_ERROR_INVALID_PARAMETER;
660 }
661
662 if (width < 1 || height < 1) {
663 ALOGE("%s: image dimension must be positive: w:%d h:%d",
664 __FUNCTION__, width, height);
665 return AMEDIA_ERROR_INVALID_PARAMETER;
666 }
667
668 if (maxImages < 1) {
669 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
670 __FUNCTION__, maxImages);
671 return AMEDIA_ERROR_INVALID_PARAMETER;
672 }
673
674 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
675 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
676 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
677 return AMEDIA_ERROR_INVALID_PARAMETER;
678 }
679
680 if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
681 ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
682 __FUNCTION__, format, usage);
683 return AMEDIA_ERROR_INVALID_PARAMETER;
684 }
685 return AMEDIA_OK;
686}
687
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700688static native_handle_t *convertHalTokenToNativeHandle(
689 const HalToken &halToken) {
690 // We attempt to store halToken in the ints of the native_handle_t after its
691 // size. The first int stores the size of the token. We store this in an int
692 // to avoid alignment issues where size_t and int do not have the same
693 // alignment.
694 size_t nhDataByteSize = halToken.size();
695 if (nhDataByteSize > kWindowHalTokenSizeMax) {
696 // The size of the token isn't reasonable..
697 return nullptr;
698 }
699 size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
700
701 // We don't check for overflow, whether numInts can fit in an int, since we
702 // expect kWindowHalTokenSizeMax to be a reasonable limit.
703 // create a native_handle_t with 0 numFds and numInts number of ints.
704 native_handle_t *nh =
705 native_handle_create(0, numInts);
706 if (!nh) {
707 return nullptr;
708 }
709 // Store the size of the token in the first int.
710 nh->data[0] = nhDataByteSize;
711 memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
712 return nh;
713}
714
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800715EXPORT
716media_status_t AImageReader_new(
717 int32_t width, int32_t height, int32_t format, int32_t maxImages,
718 /*out*/AImageReader** reader) {
719 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800720 return AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700721 width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800722}
723
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700724extern "C" {
725
726EXPORT
727media_status_t AImageReader_getWindowNativeHandle(
728 AImageReader *reader, /*out*/native_handle_t **handle) {
729 if (reader == nullptr || handle == nullptr) {
730 return AMEDIA_ERROR_INVALID_PARAMETER;
731 }
732 return reader->getWindowNativeHandle(handle);
733}
734
735} //extern "C"
736
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800737EXPORT
Sally Qida6ca842022-01-10 16:10:28 -0800738media_status_t AImageReader_newWithDataSpace(
739 int32_t width, int32_t height, uint64_t usage, int32_t maxImages,
740 uint32_t hardwareBufferFormat, int32_t dataSpace,
741 /*out*/ AImageReader** reader) {
742 ALOGV("%s", __FUNCTION__);
743
744 android_dataspace halDataSpace = static_cast<android_dataspace>(dataSpace);
745 int32_t format = static_cast<int32_t>(
746 mapHalFormatDataspaceToPublicFormat(hardwareBufferFormat, halDataSpace));
747 return AImageReader_newWithUsage(width, height, format, usage, maxImages, reader);
748}
749
750EXPORT
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800751media_status_t AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700752 int32_t width, int32_t height, int32_t format, uint64_t usage,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800753 int32_t maxImages, /*out*/ AImageReader** reader) {
754 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800755
Sally Qida6ca842022-01-10 16:10:28 -0800756 validateParameters(width, height, format, usage, maxImages, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800757
Sally Qida6ca842022-01-10 16:10:28 -0800758 PublicFormat publicFormat = static_cast<PublicFormat>(format);
759 uint32_t halFormat = mapPublicFormatToHalFormat(publicFormat);
760 android_dataspace halDataSpace = mapPublicFormatToHalDataspace(publicFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800761
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800762 AImageReader* tmpReader = new AImageReader(
Sally Qida6ca842022-01-10 16:10:28 -0800763 width, height, format, usage, maxImages, halFormat, halDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800764 if (tmpReader == nullptr) {
765 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
766 return AMEDIA_ERROR_UNKNOWN;
767 }
768 media_status_t ret = tmpReader->init();
769 if (ret != AMEDIA_OK) {
770 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
771 delete tmpReader;
772 return ret;
773 }
774 *reader = tmpReader;
775 (*reader)->incStrong((void*) AImageReader_new);
776 return AMEDIA_OK;
777}
778
779EXPORT
780void AImageReader_delete(AImageReader* reader) {
781 ALOGV("%s", __FUNCTION__);
782 if (reader != nullptr) {
Jayant Chowdhary9e0302f2019-07-16 11:04:06 -0700783 reader->close();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800784 reader->decStrong((void*) AImageReader_delete);
785 }
786 return;
787}
788
789EXPORT
790media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
Yin-Chia Yehe2ded212017-11-08 15:51:02 -0800791 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800792 if (reader == nullptr || window == nullptr) {
793 ALOGE("%s: invalid argument. reader %p, window %p",
794 __FUNCTION__, reader, window);
795 return AMEDIA_ERROR_INVALID_PARAMETER;
796 }
797 *window = reader->getWindow();
798 return AMEDIA_OK;
799}
800
801EXPORT
802media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
803 ALOGV("%s", __FUNCTION__);
804 if (reader == nullptr || width == nullptr) {
805 ALOGE("%s: invalid argument. reader %p, width %p",
806 __FUNCTION__, reader, width);
807 return AMEDIA_ERROR_INVALID_PARAMETER;
808 }
809 *width = reader->getWidth();
810 return AMEDIA_OK;
811}
812
813EXPORT
814media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
815 ALOGV("%s", __FUNCTION__);
816 if (reader == nullptr || height == nullptr) {
817 ALOGE("%s: invalid argument. reader %p, height %p",
818 __FUNCTION__, reader, height);
819 return AMEDIA_ERROR_INVALID_PARAMETER;
820 }
821 *height = reader->getHeight();
822 return AMEDIA_OK;
823}
824
825EXPORT
826media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
827 ALOGV("%s", __FUNCTION__);
828 if (reader == nullptr || format == nullptr) {
829 ALOGE("%s: invalid argument. reader %p, format %p",
830 __FUNCTION__, reader, format);
831 return AMEDIA_ERROR_INVALID_PARAMETER;
832 }
833 *format = reader->getFormat();
834 return AMEDIA_OK;
835}
836
837EXPORT
838media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
839 ALOGV("%s", __FUNCTION__);
840 if (reader == nullptr || maxImages == nullptr) {
841 ALOGE("%s: invalid argument. reader %p, maxImages %p",
842 __FUNCTION__, reader, maxImages);
843 return AMEDIA_ERROR_INVALID_PARAMETER;
844 }
845 *maxImages = reader->getMaxImages();
846 return AMEDIA_OK;
847}
848
849EXPORT
850media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
851 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800852 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800853}
854
855EXPORT
856media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
857 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800858 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
859}
860
861EXPORT
862media_status_t AImageReader_acquireNextImageAsync(
863 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
864 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800865 if (reader == nullptr || image == nullptr) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800866 ALOGE("%s: invalid argument. reader %p, image %p",
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800867 __FUNCTION__, reader, image);
868 return AMEDIA_ERROR_INVALID_PARAMETER;
869 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800870 return reader->acquireNextImage(image, acquireFenceFd);
871}
872
873EXPORT
874media_status_t AImageReader_acquireLatestImageAsync(
875 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
876 ALOGV("%s", __FUNCTION__);
877 if (reader == nullptr || image == nullptr) {
878 ALOGE("%s: invalid argument. reader %p, image %p",
879 __FUNCTION__, reader, image);
880 return AMEDIA_ERROR_INVALID_PARAMETER;
881 }
882 return reader->acquireLatestImage(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800883}
884
885EXPORT
886media_status_t AImageReader_setImageListener(
887 AImageReader* reader, AImageReader_ImageListener* listener) {
888 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700889 if (reader == nullptr) {
890 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800891 return AMEDIA_ERROR_INVALID_PARAMETER;
892 }
893
894 reader->setImageListener(listener);
895 return AMEDIA_OK;
896}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800897
898EXPORT
899media_status_t AImageReader_setBufferRemovedListener(
900 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
901 ALOGV("%s", __FUNCTION__);
902 if (reader == nullptr) {
903 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
904 return AMEDIA_ERROR_INVALID_PARAMETER;
905 }
906
907 reader->setBufferRemovedListener(listener);
908 return AMEDIA_OK;
909}