blob: c0aee90a6f00fba83c0ae291b2244ea315cdbd15 [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>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080028#include <android_runtime/android_view_Surface.h>
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080029#include <android_runtime/android_hardware_HardwareBuffer.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080030
31using namespace android;
32
33namespace {
34 // Get an ID that's unique within this process.
35 static int32_t createProcessUniqueId() {
36 static volatile int32_t globalCounter = 0;
37 return android_atomic_inc(&globalCounter);
38 }
39}
40
41const char* AImageReader::kCallbackFpKey = "Callback";
42const char* AImageReader::kContextKey = "Context";
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080043const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
Yin-Chia Yehc3603822016-01-18 22:11:19 -080044
45bool
46AImageReader::isSupportedFormat(int32_t format) {
47 switch (format) {
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080048 case AIMAGE_FORMAT_RGBA_8888:
49 case AIMAGE_FORMAT_RGBX_8888:
50 case AIMAGE_FORMAT_RGB_888:
51 case AIMAGE_FORMAT_RGB_565:
52 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080053 case AIMAGE_FORMAT_YUV_420_888:
54 case AIMAGE_FORMAT_JPEG:
55 case AIMAGE_FORMAT_RAW16:
56 case AIMAGE_FORMAT_RAW_PRIVATE:
57 case AIMAGE_FORMAT_RAW10:
58 case AIMAGE_FORMAT_RAW12:
59 case AIMAGE_FORMAT_DEPTH16:
60 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
61 return true;
62 default:
63 return false;
64 }
65}
66
67int
68AImageReader::getNumPlanesForFormat(int32_t format) {
69 switch (format) {
70 case AIMAGE_FORMAT_YUV_420_888:
71 return 3;
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080072 case AIMAGE_FORMAT_RGBA_8888:
73 case AIMAGE_FORMAT_RGBX_8888:
74 case AIMAGE_FORMAT_RGB_888:
75 case AIMAGE_FORMAT_RGB_565:
76 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080077 case AIMAGE_FORMAT_JPEG:
78 case AIMAGE_FORMAT_RAW16:
79 case AIMAGE_FORMAT_RAW_PRIVATE:
80 case AIMAGE_FORMAT_RAW10:
81 case AIMAGE_FORMAT_RAW12:
82 case AIMAGE_FORMAT_DEPTH16:
83 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
84 return 1;
85 default:
86 return -1;
87 }
88}
89
90void
91AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
92 Mutex::Autolock _l(mLock);
93 sp<AImageReader> reader = mReader.promote();
94 if (reader == nullptr) {
95 ALOGW("A frame is available after AImageReader closed!");
96 return; // reader has been closed
97 }
98 if (mListener.onImageAvailable == nullptr) {
99 return; // No callback registered
100 }
101
102 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
103 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
104 msg->setPointer(AImageReader::kContextKey, mListener.context);
105 msg->post();
106}
107
108media_status_t
109AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
110 Mutex::Autolock _l(mLock);
111 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700112 mListener.context = nullptr;
113 mListener.onImageAvailable = nullptr;
114 } else {
115 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800116 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800117 return AMEDIA_OK;
118}
119
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800120void
121AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
122 Mutex::Autolock _l(mLock);
123 sp<AImageReader> reader = mReader.promote();
124 if (reader == nullptr) {
125 ALOGW("A frame is available after AImageReader closed!");
126 return; // reader has been closed
127 }
128 if (mListener.onBufferRemoved == nullptr) {
129 return; // No callback registered
130 }
131
132 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
133 if (gBuffer == nullptr) {
134 ALOGW("A buffer being freed has gone away!");
135 return; // buffer is already destroyed
136 }
137
138 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
139 msg->setPointer(
140 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
141 msg->setPointer(AImageReader::kContextKey, mListener.context);
142 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
143 msg->post();
144}
145
146media_status_t
147AImageReader::BufferRemovedListener::setBufferRemovedListener(
148 AImageReader_BufferRemovedListener* listener) {
149 Mutex::Autolock _l(mLock);
150 if (listener == nullptr) {
151 mListener.context = nullptr;
152 mListener.onBufferRemoved = nullptr;
153 } else {
154 mListener = *listener;
155 }
156 return AMEDIA_OK;
157}
158
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800159media_status_t
160AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
161 return mFrameListener->setImageListener(listener);
162}
163
164media_status_t
165AImageReader::setImageListener(AImageReader_ImageListener* listener) {
166 Mutex::Autolock _l(mLock);
167 return setImageListenerLocked(listener);
168}
169
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800170media_status_t
171AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
172 return mBufferRemovedListener->setBufferRemovedListener(listener);
173}
174
175media_status_t
176AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
177 Mutex::Autolock _l(mLock);
178 return setBufferRemovedListenerLocked(listener);
179}
180
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800181void AImageReader::CallbackHandler::onMessageReceived(
182 const sp<AMessage> &msg) {
183 switch (msg->what()) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800184 case kWhatBufferRemoved:
185 {
186 AImageReader_BufferRemovedCallback onBufferRemoved;
187 void* context;
188 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
189 if (!found || onBufferRemoved == nullptr) {
190 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
191 return;
192 }
193 found = msg->findPointer(kContextKey, &context);
194 if (!found) {
195 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
196 return;
197 }
198 sp<RefBase> bufferToFree;
199 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
200 if (!found || bufferToFree == nullptr) {
201 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
202 return;
203 }
204
205 // TODO(jwcai) Someone from Android graphics team stating this should just be a
206 // static_cast.
207 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
208
209 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
210 // this AImageReader, and the reference will be gone once this function returns.
211 (*onBufferRemoved)(context, mReader, outBuffer);
212 break;
213 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800214 case kWhatImageAvailable:
215 {
216 AImageReader_ImageCallback onImageAvailable;
217 void* context;
218 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
219 if (!found || onImageAvailable == nullptr) {
220 ALOGE("%s: Cannot find onImageAvailable 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 (*onImageAvailable)(context, mReader);
229 break;
230 }
231 default:
232 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
233 break;
234 }
235}
236
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800237AImageReader::AImageReader(int32_t width,
238 int32_t height,
239 int32_t format,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800240 uint64_t usage0,
241 uint64_t usage1,
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800242 int32_t maxImages)
243 : mWidth(width),
244 mHeight(height),
245 mFormat(format),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800246 mUsage0(usage0),
247 mUsage1(usage1),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800248 mMaxImages(maxImages),
249 mNumPlanes(getNumPlanesForFormat(format)),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800250 mFrameListener(new FrameListener(this)),
251 mBufferRemovedListener(new BufferRemovedListener(this)) {}
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800252
253media_status_t
254AImageReader::init() {
255 PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
256 mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
257 mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
258
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800259 uint64_t producerUsage;
260 uint64_t consumerUsage;
261 android_hardware_HardwareBuffer_convertToGrallocUsageBits(
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800262 &producerUsage, &consumerUsage, mUsage0, mUsage1);
263 mHalUsage = consumerUsage;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800264
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800265 sp<IGraphicBufferProducer> gbProducer;
266 sp<IGraphicBufferConsumer> gbConsumer;
267 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
268
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800269 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "u%" PRIu64 "m%d-%d-%d",
270 mWidth, mHeight, mFormat, mUsage0, mUsage1, mMaxImages, getpid(),
271 createProcessUniqueId());
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800272
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800273 mBufferItemConsumer =
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800274 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800275 if (mBufferItemConsumer == nullptr) {
276 ALOGE("Failed to allocate BufferItemConsumer");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800277 return AMEDIA_ERROR_UNKNOWN;
278 }
279
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800280 mProducer = gbProducer;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800281 mBufferItemConsumer->setName(consumerName);
282 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800283 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800284
285 status_t res;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800286 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800287 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800288 ALOGE("Failed to set BufferItemConsumer buffer size");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800289 return AMEDIA_ERROR_UNKNOWN;
290 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800291 res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800292 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800293 ALOGE("Failed to set BufferItemConsumer buffer format");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800294 return AMEDIA_ERROR_UNKNOWN;
295 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800296 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800297 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800298 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800299 return AMEDIA_ERROR_UNKNOWN;
300 }
301
302 mSurface = new Surface(mProducer, /*controlledByApp*/true);
303 if (mSurface == nullptr) {
304 ALOGE("Failed to create surface");
305 return AMEDIA_ERROR_UNKNOWN;
306 }
307 mWindow = static_cast<ANativeWindow*>(mSurface.get());
308
309 for (int i = 0; i < mMaxImages; i++) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800310 BufferItem* buffer = new BufferItem;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800311 mBuffers.push_back(buffer);
312 }
313
314 mCbLooper = new ALooper;
315 mCbLooper->setName(consumerName.string());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800316 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800317 /*runOnCallingThread*/false,
318 /*canCallJava*/ true,
319 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800320 if (res != OK) {
321 ALOGE("Failed to start the looper");
322 return AMEDIA_ERROR_UNKNOWN;
323 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800324 mHandler = new CallbackHandler(this);
325 mCbLooper->registerHandler(mHandler);
326
327 return AMEDIA_OK;
328}
329
330AImageReader::~AImageReader() {
331 Mutex::Autolock _l(mLock);
332 AImageReader_ImageListener nullListener = {nullptr, nullptr};
333 setImageListenerLocked(&nullListener);
334
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800335 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
336 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
337
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800338 if (mCbLooper != nullptr) {
339 mCbLooper->unregisterHandler(mHandler->id());
340 mCbLooper->stop();
341 }
342 mCbLooper.clear();
343 mHandler.clear();
344
345 // Close all previously acquired images
346 for (auto it = mAcquiredImages.begin();
347 it != mAcquiredImages.end(); it++) {
348 AImage* image = *it;
349 image->close();
350 }
351
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800352 // Delete Buffer Items
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800353 for (auto it = mBuffers.begin();
354 it != mBuffers.end(); it++) {
355 delete *it;
356 }
357
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800358 if (mBufferItemConsumer != nullptr) {
359 mBufferItemConsumer->abandon();
360 mBufferItemConsumer->setFrameAvailableListener(nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800361 }
362}
363
364media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800365AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800366 *image = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800367 BufferItem* buffer = getBufferItemLocked();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800368 if (buffer == nullptr) {
369 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
370 " maxImages buffers");
371 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
372 }
373
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800374 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
375 bool waitForFence = acquireFenceFd == nullptr;
376 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
377
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800378 if (res != NO_ERROR) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800379 returnBufferItemLocked(buffer);
380 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
381 if (res == INVALID_OPERATION) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800382 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
383 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800384 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
385 __FUNCTION__, strerror(-res), res);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800386 return AMEDIA_ERROR_UNKNOWN;
387 }
388 }
389 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
390 }
391
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800392 const int bufferWidth = getBufferWidth(buffer);
393 const int bufferHeight = getBufferHeight(buffer);
394 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800395 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800396
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800397 const int readerWidth = mWidth;
398 const int readerHeight = mHeight;
399 const int readerFmt = mHalFormat;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800400 const int readerUsage = mHalUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800401
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800402 // Check if the producer buffer configurations match what AImageReader configured. Add some
403 // extra checks for non-opaque formats.
404 if (!isFormatOpaque(readerFmt)) {
405 // Check if the left-top corner of the crop rect is origin, we currently assume this point
406 // is zero, will revisit this once this assumption turns out problematic.
407 Point lt = buffer->mCrop.leftTop();
408 if (lt.x != 0 || lt.y != 0) {
409 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800410 return AMEDIA_ERROR_UNKNOWN;
411 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800412
413 // Check if the producer buffer configurations match what ImageReader configured.
414 if ((bufferFmt != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
415 (readerWidth != bufferWidth || readerHeight != bufferHeight)) {
416 ALOGW("%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
417 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
418 }
419
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800420 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
421 // ImageReader requested has been supported from the producer side.
422 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
423 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
424 "configured: %x",
425 __FUNCTION__, bufferUsage, readerUsage);
426
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800427 if (readerFmt != bufferFmt) {
428 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
429 // Special casing for when producer switches to a format compatible with flexible
430 // YUV.
431 mHalFormat = bufferFmt;
432 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
433 } else {
434 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
435 // used anywhere yet.
436 mBufferItemConsumer->releaseBuffer(*buffer);
437 returnBufferItemLocked(buffer);
438
439 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
440 __FUNCTION__, bufferFmt, readerFmt);
441
442 return AMEDIA_ERROR_UNKNOWN;
443 }
444 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800445 }
446
447 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800448 *image = new AImage(this, mFormat, mUsage0, mUsage1, buffer, buffer->mTimestamp,
449 readerWidth, readerHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800450 } else {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800451 *image = new AImage(this, mFormat, mUsage0, mUsage1, buffer, buffer->mTimestamp,
452 bufferWidth, bufferHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800453 }
454 mAcquiredImages.push_back(*image);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800455
456 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
457 if (acquireFenceFd != nullptr) {
458 *acquireFenceFd = buffer->mFence->dup();
459 }
460
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800461 return AMEDIA_OK;
462}
463
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800464BufferItem*
465AImageReader::getBufferItemLocked() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800466 if (mBuffers.empty()) {
467 return nullptr;
468 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800469 // Return a BufferItem pointer and remove it from the list
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800470 auto it = mBuffers.begin();
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800471 BufferItem* buffer = *it;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800472 mBuffers.erase(it);
473 return buffer;
474}
475
476void
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800477AImageReader::returnBufferItemLocked(BufferItem* buffer) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800478 mBuffers.push_back(buffer);
479}
480
481void
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800482AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800483 BufferItem* buffer = image->mBuffer;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800484 if (buffer == nullptr) {
485 // This should not happen, but is not fatal
486 ALOGW("AImage %p has no buffer!", image);
487 return;
488 }
489
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800490 int unlockFenceFd = -1;
491 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800492 if (ret < 0) {
493 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
494 return;
495 }
496
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800497 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
498 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
499 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
500 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800501 returnBufferItemLocked(buffer);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800502 image->mBuffer = nullptr;
503
504 bool found = false;
505 // cleanup acquired image list
506 for (auto it = mAcquiredImages.begin();
507 it != mAcquiredImages.end(); it++) {
508 AImage* readerCopy = *it;
509 if (readerCopy == image) {
510 found = true;
511 mAcquiredImages.erase(it);
512 break;
513 }
514 }
515 if (!found) {
516 ALOGE("Error: AImage %p is not generated by AImageReader %p",
517 image, this);
518 }
519}
520
521int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800522AImageReader::getBufferWidth(BufferItem* buffer) {
523 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800524
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800525 if (!buffer->mCrop.isEmpty()) {
526 return buffer->mCrop.getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800527 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800528
529 return buffer->mGraphicBuffer->getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800530}
531
532int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800533AImageReader::getBufferHeight(BufferItem* buffer) {
534 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800535
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800536 if (!buffer->mCrop.isEmpty()) {
537 return buffer->mCrop.getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800538 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800539
540 return buffer->mGraphicBuffer->getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800541}
542
543media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800544AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800545 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800546 return acquireImageLocked(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800547}
548
549media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800550AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800551 if (image == nullptr) {
552 return AMEDIA_ERROR_INVALID_PARAMETER;
553 }
554 Mutex::Autolock _l(mLock);
555 *image = nullptr;
556 AImage* prevImage = nullptr;
557 AImage* nextImage = nullptr;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800558 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800559 if (prevImage == nullptr) {
560 return ret;
561 }
562 for (;;) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800563 ret = acquireImageLocked(&nextImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800564 if (nextImage == nullptr) {
565 *image = prevImage;
566 return AMEDIA_OK;
567 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800568
569 if (acquireFenceFd == nullptr) {
570 // No need for release fence here since the prevImage is unused and acquireImageLocked
571 // has already waited for acquired fence to be signaled.
572 prevImage->close();
573 } else {
574 // Use the acquire fence as release fence, so that producer can wait before trying to
575 // refill the buffer.
576 prevImage->close(*acquireFenceFd);
577 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800578 prevImage->free();
579 prevImage = nextImage;
580 nextImage = nullptr;
581 }
582}
583
584EXPORT
585media_status_t AImageReader_new(
586 int32_t width, int32_t height, int32_t format, int32_t maxImages,
587 /*out*/AImageReader** reader) {
588 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800589 return AImageReader_newWithUsage(
590 width, height, format, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN, 0, maxImages, reader);
591}
592
593EXPORT
594media_status_t AImageReader_newWithUsage(
595 int32_t width, int32_t height, int32_t format, uint64_t usage0, uint64_t usage1,
596 int32_t maxImages, /*out*/ AImageReader** reader) {
597 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800598
599 if (width < 1 || height < 1) {
600 ALOGE("%s: image dimension must be positive: w:%d h:%d",
601 __FUNCTION__, width, height);
602 return AMEDIA_ERROR_INVALID_PARAMETER;
603 }
604
605 if (maxImages < 1) {
606 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
607 __FUNCTION__, maxImages);
608 return AMEDIA_ERROR_INVALID_PARAMETER;
609 }
610
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800611 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
612 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
613 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
614 return AMEDIA_ERROR_INVALID_PARAMETER;
615 }
616
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800617 if (!AImageReader::isSupportedFormat(format)) {
618 ALOGE("%s: format %d is not supported by AImageReader",
619 __FUNCTION__, format);
620 return AMEDIA_ERROR_INVALID_PARAMETER;
621 }
622
623 if (reader == nullptr) {
624 ALOGE("%s: reader argument is null", __FUNCTION__);
625 return AMEDIA_ERROR_INVALID_PARAMETER;
626 }
627
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800628 AImageReader* tmpReader = new AImageReader(
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800629 width, height, format, usage0, usage1, maxImages);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800630 if (tmpReader == nullptr) {
631 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
632 return AMEDIA_ERROR_UNKNOWN;
633 }
634 media_status_t ret = tmpReader->init();
635 if (ret != AMEDIA_OK) {
636 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
637 delete tmpReader;
638 return ret;
639 }
640 *reader = tmpReader;
641 (*reader)->incStrong((void*) AImageReader_new);
642 return AMEDIA_OK;
643}
644
645EXPORT
646void AImageReader_delete(AImageReader* reader) {
647 ALOGV("%s", __FUNCTION__);
648 if (reader != nullptr) {
649 reader->decStrong((void*) AImageReader_delete);
650 }
651 return;
652}
653
654EXPORT
655media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
656 ALOGE("%s", __FUNCTION__);
657 if (reader == nullptr || window == nullptr) {
658 ALOGE("%s: invalid argument. reader %p, window %p",
659 __FUNCTION__, reader, window);
660 return AMEDIA_ERROR_INVALID_PARAMETER;
661 }
662 *window = reader->getWindow();
663 return AMEDIA_OK;
664}
665
666EXPORT
667media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
668 ALOGV("%s", __FUNCTION__);
669 if (reader == nullptr || width == nullptr) {
670 ALOGE("%s: invalid argument. reader %p, width %p",
671 __FUNCTION__, reader, width);
672 return AMEDIA_ERROR_INVALID_PARAMETER;
673 }
674 *width = reader->getWidth();
675 return AMEDIA_OK;
676}
677
678EXPORT
679media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
680 ALOGV("%s", __FUNCTION__);
681 if (reader == nullptr || height == nullptr) {
682 ALOGE("%s: invalid argument. reader %p, height %p",
683 __FUNCTION__, reader, height);
684 return AMEDIA_ERROR_INVALID_PARAMETER;
685 }
686 *height = reader->getHeight();
687 return AMEDIA_OK;
688}
689
690EXPORT
691media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
692 ALOGV("%s", __FUNCTION__);
693 if (reader == nullptr || format == nullptr) {
694 ALOGE("%s: invalid argument. reader %p, format %p",
695 __FUNCTION__, reader, format);
696 return AMEDIA_ERROR_INVALID_PARAMETER;
697 }
698 *format = reader->getFormat();
699 return AMEDIA_OK;
700}
701
702EXPORT
703media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
704 ALOGV("%s", __FUNCTION__);
705 if (reader == nullptr || maxImages == nullptr) {
706 ALOGE("%s: invalid argument. reader %p, maxImages %p",
707 __FUNCTION__, reader, maxImages);
708 return AMEDIA_ERROR_INVALID_PARAMETER;
709 }
710 *maxImages = reader->getMaxImages();
711 return AMEDIA_OK;
712}
713
714EXPORT
715media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
716 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800717 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800718}
719
720EXPORT
721media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
722 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800723 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
724}
725
726EXPORT
727media_status_t AImageReader_acquireNextImageAsync(
728 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
729 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800730 if (reader == nullptr || image == nullptr) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800731 ALOGE("%s: invalid argument. reader %p, image %p",
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800732 __FUNCTION__, reader, image);
733 return AMEDIA_ERROR_INVALID_PARAMETER;
734 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800735 return reader->acquireNextImage(image, acquireFenceFd);
736}
737
738EXPORT
739media_status_t AImageReader_acquireLatestImageAsync(
740 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
741 ALOGV("%s", __FUNCTION__);
742 if (reader == nullptr || image == nullptr) {
743 ALOGE("%s: invalid argument. reader %p, image %p",
744 __FUNCTION__, reader, image);
745 return AMEDIA_ERROR_INVALID_PARAMETER;
746 }
747 return reader->acquireLatestImage(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800748}
749
750EXPORT
751media_status_t AImageReader_setImageListener(
752 AImageReader* reader, AImageReader_ImageListener* listener) {
753 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700754 if (reader == nullptr) {
755 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800756 return AMEDIA_ERROR_INVALID_PARAMETER;
757 }
758
759 reader->setImageListener(listener);
760 return AMEDIA_OK;
761}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800762
763EXPORT
764media_status_t AImageReader_setBufferRemovedListener(
765 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
766 ALOGV("%s", __FUNCTION__);
767 if (reader == nullptr) {
768 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
769 return AMEDIA_ERROR_INVALID_PARAMETER;
770 }
771
772 reader->setBufferRemovedListener(listener);
773 return AMEDIA_OK;
774}