blob: 47b0780f9fe7c063a695941501a032501c9ca8d2 [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>
Jayant Chowdhary249e1f22018-09-24 15:07:45 -070031#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080032
33using namespace android;
34
35namespace {
36 // Get an ID that's unique within this process.
37 static int32_t createProcessUniqueId() {
38 static volatile int32_t globalCounter = 0;
39 return android_atomic_inc(&globalCounter);
40 }
41}
42
43const char* AImageReader::kCallbackFpKey = "Callback";
44const char* AImageReader::kContextKey = "Context";
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080045const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
Yin-Chia Yehc3603822016-01-18 22:11:19 -080046
Jayant Chowdhary249e1f22018-09-24 15:07:45 -070047static constexpr int kWindowHalTokenSizeMax = 256;
48
49static native_handle_t *convertHalTokenToNativeHandle(const HalToken &halToken);
50
Yin-Chia Yehc3603822016-01-18 22:11:19 -080051bool
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070052AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
53 // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
54 // AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN (0x6) is sufficient as it implies
55 // AHARDWAREBUFFER_USAGE_CPU_READ (0x2).
56 bool hasCpuUsage = usage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080057 switch (format) {
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080058 case AIMAGE_FORMAT_RGBA_8888:
59 case AIMAGE_FORMAT_RGBX_8888:
60 case AIMAGE_FORMAT_RGB_888:
61 case AIMAGE_FORMAT_RGB_565:
62 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080063 case AIMAGE_FORMAT_YUV_420_888:
64 case AIMAGE_FORMAT_JPEG:
65 case AIMAGE_FORMAT_RAW16:
66 case AIMAGE_FORMAT_RAW_PRIVATE:
67 case AIMAGE_FORMAT_RAW10:
68 case AIMAGE_FORMAT_RAW12:
69 case AIMAGE_FORMAT_DEPTH16:
70 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
71 return true;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070072 case AIMAGE_FORMAT_PRIVATE:
73 // For private format, cpu usage is prohibited.
74 return !hasCpuUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080075 default:
76 return false;
77 }
78}
79
80int
81AImageReader::getNumPlanesForFormat(int32_t format) {
82 switch (format) {
83 case AIMAGE_FORMAT_YUV_420_888:
84 return 3;
Jiwen 'Steve' Caide2a5442017-02-08 14:41:41 -080085 case AIMAGE_FORMAT_RGBA_8888:
86 case AIMAGE_FORMAT_RGBX_8888:
87 case AIMAGE_FORMAT_RGB_888:
88 case AIMAGE_FORMAT_RGB_565:
89 case AIMAGE_FORMAT_RGBA_FP16:
Yin-Chia Yehc3603822016-01-18 22:11:19 -080090 case AIMAGE_FORMAT_JPEG:
91 case AIMAGE_FORMAT_RAW16:
92 case AIMAGE_FORMAT_RAW_PRIVATE:
93 case AIMAGE_FORMAT_RAW10:
94 case AIMAGE_FORMAT_RAW12:
95 case AIMAGE_FORMAT_DEPTH16:
96 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
97 return 1;
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -070098 case AIMAGE_FORMAT_PRIVATE:
99 return 0;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800100 default:
101 return -1;
102 }
103}
104
105void
106AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
107 Mutex::Autolock _l(mLock);
108 sp<AImageReader> reader = mReader.promote();
109 if (reader == nullptr) {
110 ALOGW("A frame is available after AImageReader closed!");
111 return; // reader has been closed
112 }
113 if (mListener.onImageAvailable == nullptr) {
114 return; // No callback registered
115 }
116
117 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
118 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
119 msg->setPointer(AImageReader::kContextKey, mListener.context);
120 msg->post();
121}
122
123media_status_t
124AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
125 Mutex::Autolock _l(mLock);
126 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700127 mListener.context = nullptr;
128 mListener.onImageAvailable = nullptr;
129 } else {
130 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800131 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800132 return AMEDIA_OK;
133}
134
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800135void
136AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
137 Mutex::Autolock _l(mLock);
138 sp<AImageReader> reader = mReader.promote();
139 if (reader == nullptr) {
140 ALOGW("A frame is available after AImageReader closed!");
141 return; // reader has been closed
142 }
143 if (mListener.onBufferRemoved == nullptr) {
144 return; // No callback registered
145 }
146
147 sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
148 if (gBuffer == nullptr) {
149 ALOGW("A buffer being freed has gone away!");
150 return; // buffer is already destroyed
151 }
152
153 sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
154 msg->setPointer(
155 AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
156 msg->setPointer(AImageReader::kContextKey, mListener.context);
157 msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
158 msg->post();
159}
160
161media_status_t
162AImageReader::BufferRemovedListener::setBufferRemovedListener(
163 AImageReader_BufferRemovedListener* listener) {
164 Mutex::Autolock _l(mLock);
165 if (listener == nullptr) {
166 mListener.context = nullptr;
167 mListener.onBufferRemoved = nullptr;
168 } else {
169 mListener = *listener;
170 }
171 return AMEDIA_OK;
172}
173
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800174media_status_t
175AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
176 return mFrameListener->setImageListener(listener);
177}
178
179media_status_t
180AImageReader::setImageListener(AImageReader_ImageListener* listener) {
181 Mutex::Autolock _l(mLock);
182 return setImageListenerLocked(listener);
183}
184
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800185media_status_t
186AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
187 return mBufferRemovedListener->setBufferRemovedListener(listener);
188}
189
190media_status_t
191AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
192 Mutex::Autolock _l(mLock);
193 return setBufferRemovedListenerLocked(listener);
194}
195
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800196void AImageReader::CallbackHandler::onMessageReceived(
197 const sp<AMessage> &msg) {
198 switch (msg->what()) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800199 case kWhatBufferRemoved:
200 {
201 AImageReader_BufferRemovedCallback onBufferRemoved;
202 void* context;
203 bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
204 if (!found || onBufferRemoved == nullptr) {
205 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
206 return;
207 }
208 found = msg->findPointer(kContextKey, &context);
209 if (!found) {
210 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
211 return;
212 }
213 sp<RefBase> bufferToFree;
214 found = msg->findObject(kGraphicBufferKey, &bufferToFree);
215 if (!found || bufferToFree == nullptr) {
216 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
217 return;
218 }
219
220 // TODO(jwcai) Someone from Android graphics team stating this should just be a
221 // static_cast.
222 AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
223
224 // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
225 // this AImageReader, and the reference will be gone once this function returns.
226 (*onBufferRemoved)(context, mReader, outBuffer);
227 break;
228 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800229 case kWhatImageAvailable:
230 {
231 AImageReader_ImageCallback onImageAvailable;
232 void* context;
233 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
234 if (!found || onImageAvailable == nullptr) {
235 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
236 return;
237 }
238 found = msg->findPointer(kContextKey, &context);
239 if (!found) {
240 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
241 return;
242 }
243 (*onImageAvailable)(context, mReader);
244 break;
245 }
246 default:
247 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
248 break;
249 }
250}
251
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800252AImageReader::AImageReader(int32_t width,
253 int32_t height,
254 int32_t format,
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700255 uint64_t usage,
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800256 int32_t maxImages)
257 : mWidth(width),
258 mHeight(height),
259 mFormat(format),
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700260 mUsage(usage),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800261 mMaxImages(maxImages),
262 mNumPlanes(getNumPlanesForFormat(format)),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800263 mFrameListener(new FrameListener(this)),
264 mBufferRemovedListener(new BufferRemovedListener(this)) {}
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800265
266media_status_t
267AImageReader::init() {
268 PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
269 mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
270 mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700271 mHalUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800272
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800273 sp<IGraphicBufferProducer> gbProducer;
274 sp<IGraphicBufferConsumer> gbConsumer;
275 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
276
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700277 String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
278 mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800279 createProcessUniqueId());
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800280
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800281 mBufferItemConsumer =
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800282 new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800283 if (mBufferItemConsumer == nullptr) {
284 ALOGE("Failed to allocate BufferItemConsumer");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800285 return AMEDIA_ERROR_UNKNOWN;
286 }
287
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800288 mProducer = gbProducer;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800289 mBufferItemConsumer->setName(consumerName);
290 mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800291 mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800292
293 status_t res;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800294 res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
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 size");
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->setDefaultBufferFormat(mHalFormat);
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 format");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800302 return AMEDIA_ERROR_UNKNOWN;
303 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800304 res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800305 if (res != OK) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800306 ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800307 return AMEDIA_ERROR_UNKNOWN;
308 }
309
310 mSurface = new Surface(mProducer, /*controlledByApp*/true);
311 if (mSurface == nullptr) {
312 ALOGE("Failed to create surface");
313 return AMEDIA_ERROR_UNKNOWN;
314 }
315 mWindow = static_cast<ANativeWindow*>(mSurface.get());
316
317 for (int i = 0; i < mMaxImages; i++) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800318 BufferItem* buffer = new BufferItem;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800319 mBuffers.push_back(buffer);
320 }
321
322 mCbLooper = new ALooper;
323 mCbLooper->setName(consumerName.string());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800324 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800325 /*runOnCallingThread*/false,
326 /*canCallJava*/ true,
327 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800328 if (res != OK) {
329 ALOGE("Failed to start the looper");
330 return AMEDIA_ERROR_UNKNOWN;
331 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800332 mHandler = new CallbackHandler(this);
333 mCbLooper->registerHandler(mHandler);
334
335 return AMEDIA_OK;
336}
337
338AImageReader::~AImageReader() {
339 Mutex::Autolock _l(mLock);
340 AImageReader_ImageListener nullListener = {nullptr, nullptr};
341 setImageListenerLocked(&nullListener);
342
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800343 AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
344 setBufferRemovedListenerLocked(&nullBufferRemovedListener);
345
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800346 if (mCbLooper != nullptr) {
347 mCbLooper->unregisterHandler(mHandler->id());
348 mCbLooper->stop();
349 }
350 mCbLooper.clear();
351 mHandler.clear();
352
353 // Close all previously acquired images
354 for (auto it = mAcquiredImages.begin();
355 it != mAcquiredImages.end(); it++) {
356 AImage* image = *it;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800357 Mutex::Autolock _l(image->mLock);
Yin-Chia Yeh55fc8e72017-09-19 17:28:25 -0700358 releaseImageLocked(image, /*releaseFenceFd*/-1);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800359 }
360
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800361 // Delete Buffer Items
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800362 for (auto it = mBuffers.begin();
363 it != mBuffers.end(); it++) {
364 delete *it;
365 }
366
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800367 if (mBufferItemConsumer != nullptr) {
368 mBufferItemConsumer->abandon();
369 mBufferItemConsumer->setFrameAvailableListener(nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800370 }
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700371
372 if (mWindowHandle != nullptr) {
373 int size = mWindowHandle->data[0];
374 hidl_vec<uint8_t> halToken;
375 halToken.setToExternal(
376 reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
377 deleteHalToken(halToken);
378 native_handle_delete(mWindowHandle);
379 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800380}
381
382media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800383AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800384 *image = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800385 BufferItem* buffer = getBufferItemLocked();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800386 if (buffer == nullptr) {
387 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
388 " maxImages buffers");
389 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
390 }
391
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800392 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
393 bool waitForFence = acquireFenceFd == nullptr;
394 status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
395
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800396 if (res != NO_ERROR) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800397 returnBufferItemLocked(buffer);
398 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
399 if (res == INVALID_OPERATION) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800400 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
401 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800402 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
403 __FUNCTION__, strerror(-res), res);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800404 return AMEDIA_ERROR_UNKNOWN;
405 }
406 }
407 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
408 }
409
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800410 const int bufferWidth = getBufferWidth(buffer);
411 const int bufferHeight = getBufferHeight(buffer);
412 const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800413 const int bufferUsage = buffer->mGraphicBuffer->getUsage();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800414
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800415 const int readerWidth = mWidth;
416 const int readerHeight = mHeight;
417 const int readerFmt = mHalFormat;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800418 const int readerUsage = mHalUsage;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800419
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800420 // Check if the producer buffer configurations match what AImageReader configured. Add some
421 // extra checks for non-opaque formats.
422 if (!isFormatOpaque(readerFmt)) {
423 // Check if the left-top corner of the crop rect is origin, we currently assume this point
424 // is zero, will revisit this once this assumption turns out problematic.
425 Point lt = buffer->mCrop.leftTop();
426 if (lt.x != 0 || lt.y != 0) {
427 ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800428 return AMEDIA_ERROR_UNKNOWN;
429 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800430
431 // Check if the producer buffer configurations match what ImageReader configured.
Jiwen 'Steve' Cai755ca9b2017-03-31 16:59:50 -0700432 ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
433 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
434 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800435
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800436 // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
437 // ImageReader requested has been supported from the producer side.
438 ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
439 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
440 "configured: %x",
441 __FUNCTION__, bufferUsage, readerUsage);
442
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800443 if (readerFmt != bufferFmt) {
444 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
445 // Special casing for when producer switches to a format compatible with flexible
446 // YUV.
447 mHalFormat = bufferFmt;
448 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
449 } else {
450 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
451 // used anywhere yet.
452 mBufferItemConsumer->releaseBuffer(*buffer);
453 returnBufferItemLocked(buffer);
454
455 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
456 __FUNCTION__, bufferFmt, readerFmt);
457
458 return AMEDIA_ERROR_UNKNOWN;
459 }
460 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800461 }
462
463 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700464 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800465 readerWidth, readerHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800466 } else {
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700467 *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800468 bufferWidth, bufferHeight, mNumPlanes);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800469 }
470 mAcquiredImages.push_back(*image);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800471
472 // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
473 if (acquireFenceFd != nullptr) {
474 *acquireFenceFd = buffer->mFence->dup();
475 }
476
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800477 return AMEDIA_OK;
478}
479
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800480BufferItem*
481AImageReader::getBufferItemLocked() {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800482 if (mBuffers.empty()) {
483 return nullptr;
484 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800485 // Return a BufferItem pointer and remove it from the list
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800486 auto it = mBuffers.begin();
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800487 BufferItem* buffer = *it;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800488 mBuffers.erase(it);
489 return buffer;
490}
491
492void
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800493AImageReader::returnBufferItemLocked(BufferItem* buffer) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800494 mBuffers.push_back(buffer);
495}
496
497void
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800498AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800499 BufferItem* buffer = image->mBuffer;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800500 if (buffer == nullptr) {
501 // This should not happen, but is not fatal
502 ALOGW("AImage %p has no buffer!", image);
503 return;
504 }
505
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800506 int unlockFenceFd = -1;
507 media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800508 if (ret < 0) {
509 ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
510 return;
511 }
512
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800513 sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
514 sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
515 sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
516 mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800517 returnBufferItemLocked(buffer);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800518 image->mBuffer = nullptr;
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800519 image->mLockedBuffer = nullptr;
520 image->mIsClosed = true;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800521
522 bool found = false;
523 // cleanup acquired image list
524 for (auto it = mAcquiredImages.begin();
525 it != mAcquiredImages.end(); it++) {
526 AImage* readerCopy = *it;
527 if (readerCopy == image) {
528 found = true;
529 mAcquiredImages.erase(it);
530 break;
531 }
532 }
533 if (!found) {
534 ALOGE("Error: AImage %p is not generated by AImageReader %p",
535 image, this);
536 }
537}
538
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700539media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
540 if (mWindowHandle != nullptr) {
541 *handle = mWindowHandle;
542 return AMEDIA_OK;
543 }
544 sp<HGraphicBufferProducer> hgbp =
545 new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
546 HalToken halToken;
547 if (!createHalToken(hgbp, &halToken)) {
548 return AMEDIA_ERROR_UNKNOWN;
549 }
550 mWindowHandle = convertHalTokenToNativeHandle(halToken);
551 if (!mWindowHandle) {
552 return AMEDIA_ERROR_UNKNOWN;
553 }
554 *handle = mWindowHandle;
555 return AMEDIA_OK;
556}
557
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800558int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800559AImageReader::getBufferWidth(BufferItem* buffer) {
560 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800561
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800562 if (!buffer->mCrop.isEmpty()) {
563 return buffer->mCrop.getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800564 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800565
566 return buffer->mGraphicBuffer->getWidth();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800567}
568
569int
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800570AImageReader::getBufferHeight(BufferItem* buffer) {
571 if (buffer == NULL) return -1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800572
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800573 if (!buffer->mCrop.isEmpty()) {
574 return buffer->mCrop.getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800575 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800576
577 return buffer->mGraphicBuffer->getHeight();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800578}
579
580media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800581AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800582 Mutex::Autolock _l(mLock);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800583 return acquireImageLocked(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800584}
585
586media_status_t
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800587AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800588 if (image == nullptr) {
589 return AMEDIA_ERROR_INVALID_PARAMETER;
590 }
591 Mutex::Autolock _l(mLock);
592 *image = nullptr;
593 AImage* prevImage = nullptr;
594 AImage* nextImage = nullptr;
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800595 media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800596 if (prevImage == nullptr) {
597 return ret;
598 }
599 for (;;) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800600 ret = acquireImageLocked(&nextImage, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800601 if (nextImage == nullptr) {
602 *image = prevImage;
603 return AMEDIA_OK;
604 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800605
606 if (acquireFenceFd == nullptr) {
607 // No need for release fence here since the prevImage is unused and acquireImageLocked
608 // has already waited for acquired fence to be signaled.
609 prevImage->close();
610 } else {
611 // Use the acquire fence as release fence, so that producer can wait before trying to
612 // refill the buffer.
613 prevImage->close(*acquireFenceFd);
614 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800615 prevImage->free();
616 prevImage = nextImage;
617 nextImage = nullptr;
618 }
619}
620
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700621static native_handle_t *convertHalTokenToNativeHandle(
622 const HalToken &halToken) {
623 // We attempt to store halToken in the ints of the native_handle_t after its
624 // size. The first int stores the size of the token. We store this in an int
625 // to avoid alignment issues where size_t and int do not have the same
626 // alignment.
627 size_t nhDataByteSize = halToken.size();
628 if (nhDataByteSize > kWindowHalTokenSizeMax) {
629 // The size of the token isn't reasonable..
630 return nullptr;
631 }
632 size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
633
634 // We don't check for overflow, whether numInts can fit in an int, since we
635 // expect kWindowHalTokenSizeMax to be a reasonable limit.
636 // create a native_handle_t with 0 numFds and numInts number of ints.
637 native_handle_t *nh =
638 native_handle_create(0, numInts);
639 if (!nh) {
640 return nullptr;
641 }
642 // Store the size of the token in the first int.
643 nh->data[0] = nhDataByteSize;
644 memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
645 return nh;
646}
647
648static sp<HGraphicBufferProducer> convertNativeHandleToHGBP (
649 const native_handle_t *handle) {
650 // Read the size of the halToken vec<uint8_t>
651 hidl_vec<uint8_t> halToken;
652 halToken.setToExternal(
653 reinterpret_cast<uint8_t *>(const_cast<int *>(&(handle->data[1]))),
654 handle->data[0]);
655 sp<HGraphicBufferProducer> hgbp =
656 HGraphicBufferProducer::castFrom(retrieveHalInterface(halToken));
657 return hgbp;
658}
659
660EXPORT
661sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(
662 const native_handle_t *handle) {
663 if (handle == nullptr) {
664 return nullptr;
665 }
666 if (handle->numFds != 0 ||
667 handle->numInts < ceil(sizeof(size_t) / sizeof(int))) {
668 return nullptr;
669 }
670 return convertNativeHandleToHGBP(handle);
671}
672
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800673EXPORT
674media_status_t AImageReader_new(
675 int32_t width, int32_t height, int32_t format, int32_t maxImages,
676 /*out*/AImageReader** reader) {
677 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800678 return AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700679 width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800680}
681
Jayant Chowdhary249e1f22018-09-24 15:07:45 -0700682extern "C" {
683
684EXPORT
685media_status_t AImageReader_getWindowNativeHandle(
686 AImageReader *reader, /*out*/native_handle_t **handle) {
687 if (reader == nullptr || handle == nullptr) {
688 return AMEDIA_ERROR_INVALID_PARAMETER;
689 }
690 return reader->getWindowNativeHandle(handle);
691}
692
693} //extern "C"
694
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800695EXPORT
696media_status_t AImageReader_newWithUsage(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700697 int32_t width, int32_t height, int32_t format, uint64_t usage,
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800698 int32_t maxImages, /*out*/ AImageReader** reader) {
699 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800700
701 if (width < 1 || height < 1) {
702 ALOGE("%s: image dimension must be positive: w:%d h:%d",
703 __FUNCTION__, width, height);
704 return AMEDIA_ERROR_INVALID_PARAMETER;
705 }
706
707 if (maxImages < 1) {
708 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
709 __FUNCTION__, maxImages);
710 return AMEDIA_ERROR_INVALID_PARAMETER;
711 }
712
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800713 if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
714 ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
715 __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
716 return AMEDIA_ERROR_INVALID_PARAMETER;
717 }
718
Jiwen 'Steve' Cai55ec2562017-04-12 15:56:41 -0700719 if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
720 ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
721 __FUNCTION__, format, usage);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800722 return AMEDIA_ERROR_INVALID_PARAMETER;
723 }
724
725 if (reader == nullptr) {
726 ALOGE("%s: reader argument is null", __FUNCTION__);
727 return AMEDIA_ERROR_INVALID_PARAMETER;
728 }
729
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800730 AImageReader* tmpReader = new AImageReader(
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700731 width, height, format, usage, maxImages);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800732 if (tmpReader == nullptr) {
733 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
734 return AMEDIA_ERROR_UNKNOWN;
735 }
736 media_status_t ret = tmpReader->init();
737 if (ret != AMEDIA_OK) {
738 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
739 delete tmpReader;
740 return ret;
741 }
742 *reader = tmpReader;
743 (*reader)->incStrong((void*) AImageReader_new);
744 return AMEDIA_OK;
745}
746
747EXPORT
748void AImageReader_delete(AImageReader* reader) {
749 ALOGV("%s", __FUNCTION__);
750 if (reader != nullptr) {
751 reader->decStrong((void*) AImageReader_delete);
752 }
753 return;
754}
755
756EXPORT
757media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
Yin-Chia Yehe2ded212017-11-08 15:51:02 -0800758 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800759 if (reader == nullptr || window == nullptr) {
760 ALOGE("%s: invalid argument. reader %p, window %p",
761 __FUNCTION__, reader, window);
762 return AMEDIA_ERROR_INVALID_PARAMETER;
763 }
764 *window = reader->getWindow();
765 return AMEDIA_OK;
766}
767
768EXPORT
769media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
770 ALOGV("%s", __FUNCTION__);
771 if (reader == nullptr || width == nullptr) {
772 ALOGE("%s: invalid argument. reader %p, width %p",
773 __FUNCTION__, reader, width);
774 return AMEDIA_ERROR_INVALID_PARAMETER;
775 }
776 *width = reader->getWidth();
777 return AMEDIA_OK;
778}
779
780EXPORT
781media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
782 ALOGV("%s", __FUNCTION__);
783 if (reader == nullptr || height == nullptr) {
784 ALOGE("%s: invalid argument. reader %p, height %p",
785 __FUNCTION__, reader, height);
786 return AMEDIA_ERROR_INVALID_PARAMETER;
787 }
788 *height = reader->getHeight();
789 return AMEDIA_OK;
790}
791
792EXPORT
793media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
794 ALOGV("%s", __FUNCTION__);
795 if (reader == nullptr || format == nullptr) {
796 ALOGE("%s: invalid argument. reader %p, format %p",
797 __FUNCTION__, reader, format);
798 return AMEDIA_ERROR_INVALID_PARAMETER;
799 }
800 *format = reader->getFormat();
801 return AMEDIA_OK;
802}
803
804EXPORT
805media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
806 ALOGV("%s", __FUNCTION__);
807 if (reader == nullptr || maxImages == nullptr) {
808 ALOGE("%s: invalid argument. reader %p, maxImages %p",
809 __FUNCTION__, reader, maxImages);
810 return AMEDIA_ERROR_INVALID_PARAMETER;
811 }
812 *maxImages = reader->getMaxImages();
813 return AMEDIA_OK;
814}
815
816EXPORT
817media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
818 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800819 return AImageReader_acquireNextImageAsync(reader, image, nullptr);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800820}
821
822EXPORT
823media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
824 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800825 return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
826}
827
828EXPORT
829media_status_t AImageReader_acquireNextImageAsync(
830 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
831 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800832 if (reader == nullptr || image == nullptr) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800833 ALOGE("%s: invalid argument. reader %p, image %p",
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800834 __FUNCTION__, reader, image);
835 return AMEDIA_ERROR_INVALID_PARAMETER;
836 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800837 return reader->acquireNextImage(image, acquireFenceFd);
838}
839
840EXPORT
841media_status_t AImageReader_acquireLatestImageAsync(
842 AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
843 ALOGV("%s", __FUNCTION__);
844 if (reader == nullptr || image == nullptr) {
845 ALOGE("%s: invalid argument. reader %p, image %p",
846 __FUNCTION__, reader, image);
847 return AMEDIA_ERROR_INVALID_PARAMETER;
848 }
849 return reader->acquireLatestImage(image, acquireFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800850}
851
852EXPORT
853media_status_t AImageReader_setImageListener(
854 AImageReader* reader, AImageReader_ImageListener* listener) {
855 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700856 if (reader == nullptr) {
857 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800858 return AMEDIA_ERROR_INVALID_PARAMETER;
859 }
860
861 reader->setImageListener(listener);
862 return AMEDIA_OK;
863}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800864
865EXPORT
866media_status_t AImageReader_setBufferRemovedListener(
867 AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
868 ALOGV("%s", __FUNCTION__);
869 if (reader == nullptr) {
870 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
871 return AMEDIA_ERROR_INVALID_PARAMETER;
872 }
873
874 reader->setBufferRemovedListener(listener);
875 return AMEDIA_OK;
876}