blob: be635ff96b6cc722846c4a2a11684ab647584e52 [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>
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -070030#include <grallocusage/GrallocUsageConversion.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080031
32using namespace android;
33
34namespace {
35 // Get an ID that's unique within this process.
36 static int32_t createProcessUniqueId() {
37 static volatile int32_t globalCounter = 0;
38 return android_atomic_inc(&globalCounter);
39 }
40}
41
42const char* AImageReader::kCallbackFpKey = "Callback";
43const char* AImageReader::kContextKey = "Context";
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080044const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
Yin-Chia Yehc3603822016-01-18 22:11:19 -080045
46bool
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070047AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
48 // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
49 // AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN (0x6) is sufficient as it implies
50 // AHARDWAREBUFFER_USAGE_CPU_READ (0x2).
51 bool hasCpuUsage = usage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080052 switch (format) {
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080053 case AIMAGE_FORMAT_RGBA_8888:
54 case AIMAGE_FORMAT_RGBX_8888:
55 case AIMAGE_FORMAT_RGB_888:
56 case AIMAGE_FORMAT_RGB_565:
57 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080058 case AIMAGE_FORMAT_YUV_420_888:
59 case AIMAGE_FORMAT_JPEG:
60 case AIMAGE_FORMAT_RAW16:
61 case AIMAGE_FORMAT_RAW_PRIVATE:
62 case AIMAGE_FORMAT_RAW10:
63 case AIMAGE_FORMAT_RAW12:
64 case AIMAGE_FORMAT_DEPTH16:
65 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
66 return true;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070067 case AIMAGE_FORMAT_PRIVATE:
68 // For private format, cpu usage is prohibited.
69 return !hasCpuUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080070 default:
71 return false;
72 }
73}
74
75int
76AImageReader::getNumPlanesForFormat(int32_t format) {
77 switch (format) {
78 case AIMAGE_FORMAT_YUV_420_888:
79 return 3;
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080080 case AIMAGE_FORMAT_RGBA_8888:
81 case AIMAGE_FORMAT_RGBX_8888:
82 case AIMAGE_FORMAT_RGB_888:
83 case AIMAGE_FORMAT_RGB_565:
84 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080085 case AIMAGE_FORMAT_JPEG:
86 case AIMAGE_FORMAT_RAW16:
87 case AIMAGE_FORMAT_RAW_PRIVATE:
88 case AIMAGE_FORMAT_RAW10:
89 case AIMAGE_FORMAT_RAW12:
90 case AIMAGE_FORMAT_DEPTH16:
91 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
92 return 1;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070093 case AIMAGE_FORMAT_PRIVATE:
94 return 0;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080095 default:
96 return -1;
97 }
98}
99
100void
101AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
102 Mutex::Autolock _l(mLock);
103 sp<AImageReader> reader = mReader.promote();
104 if (reader == nullptr) {
105 ALOGW("A frame is available after AImageReader closed!");
106 return; // reader has been closed
107 }
108 if (mListener.onImageAvailable == nullptr) {
109 return; // No callback registered
110 }
111
112 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
113 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
114 msg->setPointer(AImageReader::kContextKey, mListener.context);
115 msg->post();
116}
117
118media_status_t
119AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
120 Mutex::Autolock _l(mLock);
121 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700122 mListener.context = nullptr;
123 mListener.onImageAvailable = nullptr;
124 } else {
125 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800126 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800127 return AMEDIA_OK;
128}
129
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800130void
131AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
132 Mutex::Autolock _l(mLock);
133 sp<AImageReader> reader = mReader.promote();
134 if (reader == nullptr) {
135 ALOGW("A frame is available after AImageReader closed!");
136 return; // reader has been closed
137 }
138 if (mListener.onBufferRemoved == nullptr) {
139 return; // No callback registered
140 }
141
142 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
143 if (gBuffer == nullptr) {
144 ALOGW("A buffer being freed has gone away!");
145 return; // buffer is already destroyed
146 }
147
148 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
149 msg->setPointer(
150 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
151 msg->setPointer(AImageReader::kContextKey, mListener.context);
152 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
153 msg->post();
154}
155
156media_status_t
157AImageReader::BufferRemovedListener::setBufferRemovedListener(
158 AImageReader_BufferRemovedListener* listener) {
159 Mutex::Autolock _l(mLock);
160 if (listener == nullptr) {
161 mListener.context = nullptr;
162 mListener.onBufferRemoved = nullptr;
163 } else {
164 mListener = *listener;
165 }
166 return AMEDIA_OK;
167}
168
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800169media_status_t
170AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
171 return mFrameListener->setImageListener(listener);
172}
173
174media_status_t
175AImageReader::setImageListener(AImageReader_ImageListener* listener) {
176 Mutex::Autolock _l(mLock);
177 return setImageListenerLocked(listener);
178}
179
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800180media_status_t
181AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
182 return mBufferRemovedListener->setBufferRemovedListener(listener);
183}
184
185media_status_t
186AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
187 Mutex::Autolock _l(mLock);
188 return setBufferRemovedListenerLocked(listener);
189}
190
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800191void AImageReader::CallbackHandler::onMessageReceived(
192 const sp<AMessage> &msg) {
193 switch (msg->what()) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800194 case kWhatBufferRemoved:
195 {
196 AImageReader_BufferRemovedCallback onBufferRemoved;
197 void* context;
198 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
199 if (!found || onBufferRemoved == nullptr) {
200 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
201 return;
202 }
203 found = msg->findPointer(kContextKey, &context);
204 if (!found) {
205 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
206 return;
207 }
208 sp<RefBase> bufferToFree;
209 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
210 if (!found || bufferToFree == nullptr) {
211 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
212 return;
213 }
214
215 // TODO(jwcai) Someone from Android graphics team stating this should just be a
216 // static_cast.
217 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
218
219 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
220 // this AImageReader, and the reference will be gone once this function returns.
221 (*onBufferRemoved)(context, mReader, outBuffer);
222 break;
223 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800224 case kWhatImageAvailable:
225 {
226 AImageReader_ImageCallback onImageAvailable;
227 void* context;
228 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
229 if (!found || onImageAvailable == nullptr) {
230 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
231 return;
232 }
233 found = msg->findPointer(kContextKey, &context);
234 if (!found) {
235 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
236 return;
237 }
238 (*onImageAvailable)(context, mReader);
239 break;
240 }
241 default:
242 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
243 break;
244 }
245}
246
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800247AImageReader::AImageReader(int32_t width,
248 int32_t height,
249 int32_t format,
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700250 uint64_t usage,
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800251 int32_t maxImages)
252 : mWidth(width),
253 mHeight(height),
254 mFormat(format),
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700255 mUsage(usage),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800256 mMaxImages(maxImages),
257 mNumPlanes(getNumPlanesForFormat(format)),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800258 mFrameListener(new FrameListener(this)),
259 mBufferRemovedListener(new BufferRemovedListener(this)) {}
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800260
261media_status_t
262AImageReader::init() {
263 PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
264 mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
265 mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700266 mHalUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800267
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800268 sp<IGraphicBufferProducer> gbProducer;
269 sp<IGraphicBufferConsumer> gbConsumer;
270 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
271
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700272 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
273 mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800274 createProcessUniqueId());
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800275
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800276 mBufferItemConsumer =
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800277 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800278 if (mBufferItemConsumer == nullptr) {
279 ALOGE("Failed to allocate BufferItemConsumer");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800280 return AMEDIA_ERROR_UNKNOWN;
281 }
282
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800283 mProducer = gbProducer;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800284 mBufferItemConsumer->setName(consumerName);
285 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800286 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800287
288 status_t res;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800289 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800290 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800291 ALOGE("Failed to set BufferItemConsumer buffer size");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800292 return AMEDIA_ERROR_UNKNOWN;
293 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800294 res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800295 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800296 ALOGE("Failed to set BufferItemConsumer buffer format");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800297 return AMEDIA_ERROR_UNKNOWN;
298 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800299 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800300 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800301 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800302 return AMEDIA_ERROR_UNKNOWN;
303 }
304
305 mSurface = new Surface(mProducer, /*controlledByApp*/true);
306 if (mSurface == nullptr) {
307 ALOGE("Failed to create surface");
308 return AMEDIA_ERROR_UNKNOWN;
309 }
310 mWindow = static_cast<ANativeWindow*>(mSurface.get());
311
312 for (int i = 0; i < mMaxImages; i++) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800313 BufferItem* buffer = new BufferItem;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800314 mBuffers.push_back(buffer);
315 }
316
317 mCbLooper = new ALooper;
318 mCbLooper->setName(consumerName.string());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800319 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800320 /*runOnCallingThread*/false,
321 /*canCallJava*/ true,
322 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800323 if (res != OK) {
324 ALOGE("Failed to start the looper");
325 return AMEDIA_ERROR_UNKNOWN;
326 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800327 mHandler = new CallbackHandler(this);
328 mCbLooper->registerHandler(mHandler);
329
330 return AMEDIA_OK;
331}
332
333AImageReader::~AImageReader() {
334 Mutex::Autolock _l(mLock);
335 AImageReader_ImageListener nullListener = {nullptr, nullptr};
336 setImageListenerLocked(&nullListener);
337
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800338 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
339 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
340
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800341 if (mCbLooper != nullptr) {
342 mCbLooper->unregisterHandler(mHandler->id());
343 mCbLooper->stop();
344 }
345 mCbLooper.clear();
346 mHandler.clear();
347
348 // Close all previously acquired images
349 for (auto it = mAcquiredImages.begin();
350 it != mAcquiredImages.end(); it++) {
351 AImage* image = *it;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800352 Mutex::Autolock _l(image->mLock);
Yin-Chia Yeh55fc8e72017-09-19 17:28:25 -0700353 releaseImageLocked(image, /*releaseFenceFd*/-1);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800354 }
355
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800356 // Delete Buffer Items
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800357 for (auto it = mBuffers.begin();
358 it != mBuffers.end(); it++) {
359 delete *it;
360 }
361
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800362 if (mBufferItemConsumer != nullptr) {
363 mBufferItemConsumer->abandon();
364 mBufferItemConsumer->setFrameAvailableListener(nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800365 }
366}
367
368media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800369AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800370 *image = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800371 BufferItem* buffer = getBufferItemLocked();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800372 if (buffer == nullptr) {
373 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
374 " maxImages buffers");
375 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
376 }
377
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800378 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
379 bool waitForFence = acquireFenceFd == nullptr;
380 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
381
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800382 if (res != NO_ERROR) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800383 returnBufferItemLocked(buffer);
384 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
385 if (res == INVALID_OPERATION) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800386 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
387 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800388 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
389 __FUNCTION__, strerror(-res), res);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800390 return AMEDIA_ERROR_UNKNOWN;
391 }
392 }
393 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
394 }
395
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800396 const int bufferWidth = getBufferWidth(buffer);
397 const int bufferHeight = getBufferHeight(buffer);
398 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800399 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800400
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800401 const int readerWidth = mWidth;
402 const int readerHeight = mHeight;
403 const int readerFmt = mHalFormat;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800404 const int readerUsage = mHalUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800405
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800406 // Check if the producer buffer configurations match what AImageReader configured. Add some
407 // extra checks for non-opaque formats.
408 if (!isFormatOpaque(readerFmt)) {
409 // Check if the left-top corner of the crop rect is origin, we currently assume this point
410 // is zero, will revisit this once this assumption turns out problematic.
411 Point lt = buffer->mCrop.leftTop();
412 if (lt.x != 0 || lt.y != 0) {
413 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800414 return AMEDIA_ERROR_UNKNOWN;
415 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800416
417 // Check if the producer buffer configurations match what ImageReader configured.
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -0700418 ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
419 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
420 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800421
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800422 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
423 // ImageReader requested has been supported from the producer side.
424 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
425 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
426 "configured: %x",
427 __FUNCTION__, bufferUsage, readerUsage);
428
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800429 if (readerFmt != bufferFmt) {
430 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
431 // Special casing for when producer switches to a format compatible with flexible
432 // YUV.
433 mHalFormat = bufferFmt;
434 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
435 } else {
436 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
437 // used anywhere yet.
438 mBufferItemConsumer->releaseBuffer(*buffer);
439 returnBufferItemLocked(buffer);
440
441 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
442 __FUNCTION__, bufferFmt, readerFmt);
443
444 return AMEDIA_ERROR_UNKNOWN;
445 }
446 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800447 }
448
449 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700450 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800451 readerWidth, readerHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800452 } else {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700453 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800454 bufferWidth, bufferHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800455 }
456 mAcquiredImages.push_back(*image);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800457
458 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
459 if (acquireFenceFd != nullptr) {
460 *acquireFenceFd = buffer->mFence->dup();
461 }
462
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800463 return AMEDIA_OK;
464}
465
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800466BufferItem*
467AImageReader::getBufferItemLocked() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800468 if (mBuffers.empty()) {
469 return nullptr;
470 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800471 // Return a BufferItem pointer and remove it from the list
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800472 auto it = mBuffers.begin();
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800473 BufferItem* buffer = *it;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800474 mBuffers.erase(it);
475 return buffer;
476}
477
478void
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800479AImageReader::returnBufferItemLocked(BufferItem* buffer) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800480 mBuffers.push_back(buffer);
481}
482
483void
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800484AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800485 BufferItem* buffer = image->mBuffer;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800486 if (buffer == nullptr) {
487 // This should not happen, but is not fatal
488 ALOGW("AImage %p has no buffer!", image);
489 return;
490 }
491
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800492 int unlockFenceFd = -1;
493 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800494 if (ret < 0) {
495 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
496 return;
497 }
498
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800499 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
500 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
501 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
502 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800503 returnBufferItemLocked(buffer);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800504 image->mBuffer = nullptr;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800505 image->mLockedBuffer = nullptr;
506 image->mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800507
508 bool found = false;
509 // cleanup acquired image list
510 for (auto it = mAcquiredImages.begin();
511 it != mAcquiredImages.end(); it++) {
512 AImage* readerCopy = *it;
513 if (readerCopy == image) {
514 found = true;
515 mAcquiredImages.erase(it);
516 break;
517 }
518 }
519 if (!found) {
520 ALOGE("Error: AImage %p is not generated by AImageReader %p",
521 image, this);
522 }
523}
524
525int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800526AImageReader::getBufferWidth(BufferItem* buffer) {
527 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800528
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800529 if (!buffer->mCrop.isEmpty()) {
530 return buffer->mCrop.getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800531 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800532
533 return buffer->mGraphicBuffer->getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800534}
535
536int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800537AImageReader::getBufferHeight(BufferItem* buffer) {
538 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800539
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800540 if (!buffer->mCrop.isEmpty()) {
541 return buffer->mCrop.getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800542 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800543
544 return buffer->mGraphicBuffer->getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800545}
546
547media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800548AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800549 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800550 return acquireImageLocked(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800551}
552
553media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800554AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800555 if (image == nullptr) {
556 return AMEDIA_ERROR_INVALID_PARAMETER;
557 }
558 Mutex::Autolock _l(mLock);
559 *image = nullptr;
560 AImage* prevImage = nullptr;
561 AImage* nextImage = nullptr;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800562 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800563 if (prevImage == nullptr) {
564 return ret;
565 }
566 for (;;) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800567 ret = acquireImageLocked(&nextImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800568 if (nextImage == nullptr) {
569 *image = prevImage;
570 return AMEDIA_OK;
571 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800572
573 if (acquireFenceFd == nullptr) {
574 // No need for release fence here since the prevImage is unused and acquireImageLocked
575 // has already waited for acquired fence to be signaled.
576 prevImage->close();
577 } else {
578 // Use the acquire fence as release fence, so that producer can wait before trying to
579 // refill the buffer.
580 prevImage->close(*acquireFenceFd);
581 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800582 prevImage->free();
583 prevImage = nextImage;
584 nextImage = nullptr;
585 }
586}
587
588EXPORT
589media_status_t AImageReader_new(
590 int32_t width, int32_t height, int32_t format, int32_t maxImages,
591 /*out*/AImageReader** reader) {
592 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800593 return AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700594 width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800595}
596
597EXPORT
598media_status_t AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700599 int32_t width, int32_t height, int32_t format, uint64_t usage,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800600 int32_t maxImages, /*out*/ AImageReader** reader) {
601 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800602
603 if (width < 1 || height < 1) {
604 ALOGE("%s: image dimension must be positive: w:%d h:%d",
605 __FUNCTION__, width, height);
606 return AMEDIA_ERROR_INVALID_PARAMETER;
607 }
608
609 if (maxImages < 1) {
610 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
611 __FUNCTION__, maxImages);
612 return AMEDIA_ERROR_INVALID_PARAMETER;
613 }
614
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800615 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
616 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
617 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
618 return AMEDIA_ERROR_INVALID_PARAMETER;
619 }
620
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700621 if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
622 ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
623 __FUNCTION__, format, usage);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800624 return AMEDIA_ERROR_INVALID_PARAMETER;
625 }
626
627 if (reader == nullptr) {
628 ALOGE("%s: reader argument is null", __FUNCTION__);
629 return AMEDIA_ERROR_INVALID_PARAMETER;
630 }
631
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800632 AImageReader* tmpReader = new AImageReader(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700633 width, height, format, usage, maxImages);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800634 if (tmpReader == nullptr) {
635 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
636 return AMEDIA_ERROR_UNKNOWN;
637 }
638 media_status_t ret = tmpReader->init();
639 if (ret != AMEDIA_OK) {
640 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
641 delete tmpReader;
642 return ret;
643 }
644 *reader = tmpReader;
645 (*reader)->incStrong((void*) AImageReader_new);
646 return AMEDIA_OK;
647}
648
649EXPORT
650void AImageReader_delete(AImageReader* reader) {
651 ALOGV("%s", __FUNCTION__);
652 if (reader != nullptr) {
653 reader->decStrong((void*) AImageReader_delete);
654 }
655 return;
656}
657
658EXPORT
659media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
Yin-Chia Yehe2ded212017-11-08 15:51:02 -0800660 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800661 if (reader == nullptr || window == nullptr) {
662 ALOGE("%s: invalid argument. reader %p, window %p",
663 __FUNCTION__, reader, window);
664 return AMEDIA_ERROR_INVALID_PARAMETER;
665 }
666 *window = reader->getWindow();
667 return AMEDIA_OK;
668}
669
670EXPORT
671media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
672 ALOGV("%s", __FUNCTION__);
673 if (reader == nullptr || width == nullptr) {
674 ALOGE("%s: invalid argument. reader %p, width %p",
675 __FUNCTION__, reader, width);
676 return AMEDIA_ERROR_INVALID_PARAMETER;
677 }
678 *width = reader->getWidth();
679 return AMEDIA_OK;
680}
681
682EXPORT
683media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
684 ALOGV("%s", __FUNCTION__);
685 if (reader == nullptr || height == nullptr) {
686 ALOGE("%s: invalid argument. reader %p, height %p",
687 __FUNCTION__, reader, height);
688 return AMEDIA_ERROR_INVALID_PARAMETER;
689 }
690 *height = reader->getHeight();
691 return AMEDIA_OK;
692}
693
694EXPORT
695media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
696 ALOGV("%s", __FUNCTION__);
697 if (reader == nullptr || format == nullptr) {
698 ALOGE("%s: invalid argument. reader %p, format %p",
699 __FUNCTION__, reader, format);
700 return AMEDIA_ERROR_INVALID_PARAMETER;
701 }
702 *format = reader->getFormat();
703 return AMEDIA_OK;
704}
705
706EXPORT
707media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
708 ALOGV("%s", __FUNCTION__);
709 if (reader == nullptr || maxImages == nullptr) {
710 ALOGE("%s: invalid argument. reader %p, maxImages %p",
711 __FUNCTION__, reader, maxImages);
712 return AMEDIA_ERROR_INVALID_PARAMETER;
713 }
714 *maxImages = reader->getMaxImages();
715 return AMEDIA_OK;
716}
717
718EXPORT
719media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
720 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800721 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800722}
723
724EXPORT
725media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
726 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800727 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
728}
729
730EXPORT
731media_status_t AImageReader_acquireNextImageAsync(
732 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
733 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800734 if (reader == nullptr || image == nullptr) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800735 ALOGE("%s: invalid argument. reader %p, image %p",
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800736 __FUNCTION__, reader, image);
737 return AMEDIA_ERROR_INVALID_PARAMETER;
738 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800739 return reader->acquireNextImage(image, acquireFenceFd);
740}
741
742EXPORT
743media_status_t AImageReader_acquireLatestImageAsync(
744 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
745 ALOGV("%s", __FUNCTION__);
746 if (reader == nullptr || image == nullptr) {
747 ALOGE("%s: invalid argument. reader %p, image %p",
748 __FUNCTION__, reader, image);
749 return AMEDIA_ERROR_INVALID_PARAMETER;
750 }
751 return reader->acquireLatestImage(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800752}
753
754EXPORT
755media_status_t AImageReader_setImageListener(
756 AImageReader* reader, AImageReader_ImageListener* listener) {
757 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700758 if (reader == nullptr) {
759 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800760 return AMEDIA_ERROR_INVALID_PARAMETER;
761 }
762
763 reader->setImageListener(listener);
764 return AMEDIA_OK;
765}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800766
767EXPORT
768media_status_t AImageReader_setBufferRemovedListener(
769 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
770 ALOGV("%s", __FUNCTION__);
771 if (reader == nullptr) {
772 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
773 return AMEDIA_ERROR_INVALID_PARAMETER;
774 }
775
776 reader->setBufferRemovedListener(listener);
777 return AMEDIA_OK;
778}