blob: a3a4625cfb897c22734f705e59bcdb41dd552fd6 [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>
27#include <android_runtime/android_view_Surface.h>
28
29using namespace android;
30
31namespace {
32 // Get an ID that's unique within this process.
33 static int32_t createProcessUniqueId() {
34 static volatile int32_t globalCounter = 0;
35 return android_atomic_inc(&globalCounter);
36 }
37}
38
39const char* AImageReader::kCallbackFpKey = "Callback";
40const char* AImageReader::kContextKey = "Context";
41
42bool
43AImageReader::isSupportedFormat(int32_t format) {
44 switch (format) {
45 case AIMAGE_FORMAT_YUV_420_888:
46 case AIMAGE_FORMAT_JPEG:
47 case AIMAGE_FORMAT_RAW16:
48 case AIMAGE_FORMAT_RAW_PRIVATE:
49 case AIMAGE_FORMAT_RAW10:
50 case AIMAGE_FORMAT_RAW12:
51 case AIMAGE_FORMAT_DEPTH16:
52 case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
53 return true;
54 default:
55 return false;
56 }
57}
58
59int
60AImageReader::getNumPlanesForFormat(int32_t format) {
61 switch (format) {
62 case AIMAGE_FORMAT_YUV_420_888:
63 return 3;
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 1;
72 default:
73 return -1;
74 }
75}
76
77void
78AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
79 Mutex::Autolock _l(mLock);
80 sp<AImageReader> reader = mReader.promote();
81 if (reader == nullptr) {
82 ALOGW("A frame is available after AImageReader closed!");
83 return; // reader has been closed
84 }
85 if (mListener.onImageAvailable == nullptr) {
86 return; // No callback registered
87 }
88
89 sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
90 msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
91 msg->setPointer(AImageReader::kContextKey, mListener.context);
92 msg->post();
93}
94
95media_status_t
96AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
97 Mutex::Autolock _l(mLock);
98 if (listener == nullptr) {
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -070099 mListener.context = nullptr;
100 mListener.onImageAvailable = nullptr;
101 } else {
102 mListener = *listener;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800103 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800104 return AMEDIA_OK;
105}
106
107media_status_t
108AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
109 return mFrameListener->setImageListener(listener);
110}
111
112media_status_t
113AImageReader::setImageListener(AImageReader_ImageListener* listener) {
114 Mutex::Autolock _l(mLock);
115 return setImageListenerLocked(listener);
116}
117
118void AImageReader::CallbackHandler::onMessageReceived(
119 const sp<AMessage> &msg) {
120 switch (msg->what()) {
121 case kWhatImageAvailable:
122 {
123 AImageReader_ImageCallback onImageAvailable;
124 void* context;
125 bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
126 if (!found || onImageAvailable == nullptr) {
127 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
128 return;
129 }
130 found = msg->findPointer(kContextKey, &context);
131 if (!found) {
132 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
133 return;
134 }
135 (*onImageAvailable)(context, mReader);
136 break;
137 }
138 default:
139 ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
140 break;
141 }
142}
143
144AImageReader::AImageReader(int32_t width, int32_t height, int32_t format, int32_t maxImages) :
145 mWidth(width), mHeight(height), mFormat(format), mMaxImages(maxImages),
146 mNumPlanes(getNumPlanesForFormat(format)),
147 mFrameListener(new FrameListener(this)) {}
148
149media_status_t
150AImageReader::init() {
151 PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
152 mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
153 mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
154
155 sp<IGraphicBufferProducer> gbProducer;
156 sp<IGraphicBufferConsumer> gbConsumer;
157 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
158
159 sp<CpuConsumer> cpuConsumer;
160 String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
161 mWidth, mHeight, mFormat, mMaxImages, getpid(),
162 createProcessUniqueId());
163
164 cpuConsumer = new CpuConsumer(gbConsumer, mMaxImages, /*controlledByApp*/true);
165 if (cpuConsumer == nullptr) {
166 ALOGE("Failed to allocate CpuConsumer");
167 return AMEDIA_ERROR_UNKNOWN;
168 }
169
170 mCpuConsumer = cpuConsumer;
171 mCpuConsumer->setName(consumerName);
172 mProducer = gbProducer;
173
174 sp<ConsumerBase> consumer = cpuConsumer;
175 consumer->setFrameAvailableListener(mFrameListener);
176
177 status_t res;
178 res = cpuConsumer->setDefaultBufferSize(mWidth, mHeight);
179 if (res != OK) {
180 ALOGE("Failed to set CpuConsumer buffer size");
181 return AMEDIA_ERROR_UNKNOWN;
182 }
183 res = cpuConsumer->setDefaultBufferFormat(mHalFormat);
184 if (res != OK) {
185 ALOGE("Failed to set CpuConsumer buffer format");
186 return AMEDIA_ERROR_UNKNOWN;
187 }
188 res = cpuConsumer->setDefaultBufferDataSpace(mHalDataSpace);
189 if (res != OK) {
190 ALOGE("Failed to set CpuConsumer buffer dataSpace");
191 return AMEDIA_ERROR_UNKNOWN;
192 }
193
194 mSurface = new Surface(mProducer, /*controlledByApp*/true);
195 if (mSurface == nullptr) {
196 ALOGE("Failed to create surface");
197 return AMEDIA_ERROR_UNKNOWN;
198 }
199 mWindow = static_cast<ANativeWindow*>(mSurface.get());
200
201 for (int i = 0; i < mMaxImages; i++) {
202 CpuConsumer::LockedBuffer* buffer = new CpuConsumer::LockedBuffer;
203 mBuffers.push_back(buffer);
204 }
205
206 mCbLooper = new ALooper;
207 mCbLooper->setName(consumerName.string());
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800208 res = mCbLooper->start(
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800209 /*runOnCallingThread*/false,
210 /*canCallJava*/ true,
211 PRIORITY_DEFAULT);
Aurimas Liutikas214c8332016-02-19 14:48:23 -0800212 if (res != OK) {
213 ALOGE("Failed to start the looper");
214 return AMEDIA_ERROR_UNKNOWN;
215 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800216 mHandler = new CallbackHandler(this);
217 mCbLooper->registerHandler(mHandler);
218
219 return AMEDIA_OK;
220}
221
222AImageReader::~AImageReader() {
223 Mutex::Autolock _l(mLock);
224 AImageReader_ImageListener nullListener = {nullptr, nullptr};
225 setImageListenerLocked(&nullListener);
226
227 if (mCbLooper != nullptr) {
228 mCbLooper->unregisterHandler(mHandler->id());
229 mCbLooper->stop();
230 }
231 mCbLooper.clear();
232 mHandler.clear();
233
234 // Close all previously acquired images
235 for (auto it = mAcquiredImages.begin();
236 it != mAcquiredImages.end(); it++) {
237 AImage* image = *it;
238 image->close();
239 }
240
241 // Delete LockedBuffers
242 for (auto it = mBuffers.begin();
243 it != mBuffers.end(); it++) {
244 delete *it;
245 }
246
247 if (mCpuConsumer != nullptr) {
248 mCpuConsumer->abandon();
249 mCpuConsumer->setFrameAvailableListener(nullptr);
250 }
251}
252
253media_status_t
254AImageReader::acquireCpuConsumerImageLocked(/*out*/AImage** image) {
255 *image = nullptr;
256 CpuConsumer::LockedBuffer* buffer = getLockedBufferLocked();
257 if (buffer == nullptr) {
258 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
259 " maxImages buffers");
260 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
261 }
262
263 status_t res = mCpuConsumer->lockNextBuffer(buffer);
264 if (res != NO_ERROR) {
265 returnLockedBufferLocked(buffer);
266 if (res != BAD_VALUE /*no buffers*/) {
267 if (res == NOT_ENOUGH_DATA) {
268 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
269 } else {
270 ALOGE("%s Fail to lockNextBuffer with error: %d ",
271 __FUNCTION__, res);
272 return AMEDIA_ERROR_UNKNOWN;
273 }
274 }
275 return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
276 }
277
278 if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
279 ALOGE("NV21 format is not supported by AImageReader");
280 return AMEDIA_ERROR_UNSUPPORTED;
281 }
282
283 // Check if the left-top corner of the crop rect is origin, we currently assume this point is
284 // zero, will revist this once this assumption turns out problematic.
285 Point lt = buffer->crop.leftTop();
286 if (lt.x != 0 || lt.y != 0) {
287 ALOGE("crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
288 return AMEDIA_ERROR_UNKNOWN;
289 }
290
291 // Check if the producer buffer configurations match what ImageReader configured.
292 int outputWidth = getBufferWidth(buffer);
293 int outputHeight = getBufferHeight(buffer);
294
295 int readerFmt = mHalFormat;
296 int readerWidth = mWidth;
297 int readerHeight = mHeight;
298
299 if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
300 (readerWidth != outputWidth || readerHeight != outputHeight)) {
301 ALOGW("%s: Producer buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
302 __FUNCTION__, outputWidth, outputHeight, readerWidth, readerHeight);
303 }
304
305 int bufFmt = buffer->format;
306 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
307 bufFmt = buffer->flexFormat;
308 }
309
310 if (readerFmt != bufFmt) {
311 if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
312 HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
313 // Special casing for when producer switches to a format compatible with flexible YUV
314 // (HAL_PIXEL_FORMAT_YCbCr_420_888).
315 mHalFormat = bufFmt;
316 ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
317 } else {
318 // Return the buffer to the queue.
319 mCpuConsumer->unlockBuffer(*buffer);
320 returnLockedBufferLocked(buffer);
321
322 ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
323 buffer->format, readerFmt);
324
325 return AMEDIA_ERROR_UNKNOWN;
326 }
327 }
328
329 if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
330 *image = new AImage(this, mFormat, buffer, buffer->timestamp,
331 readerWidth, readerHeight, mNumPlanes);
332 } else {
333 *image = new AImage(this, mFormat, buffer, buffer->timestamp,
334 outputWidth, outputHeight, mNumPlanes);
335 }
336 mAcquiredImages.push_back(*image);
337 return AMEDIA_OK;
338}
339
340CpuConsumer::LockedBuffer*
341AImageReader::getLockedBufferLocked() {
342 if (mBuffers.empty()) {
343 return nullptr;
344 }
345 // Return a LockedBuffer pointer and remove it from the list
346 auto it = mBuffers.begin();
347 CpuConsumer::LockedBuffer* buffer = *it;
348 mBuffers.erase(it);
349 return buffer;
350}
351
352void
353AImageReader::returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer) {
354 mBuffers.push_back(buffer);
355}
356
357void
358AImageReader::releaseImageLocked(AImage* image) {
359 CpuConsumer::LockedBuffer* buffer = image->mBuffer;
360 if (buffer == nullptr) {
361 // This should not happen, but is not fatal
362 ALOGW("AImage %p has no buffer!", image);
363 return;
364 }
365
366 mCpuConsumer->unlockBuffer(*buffer);
367 returnLockedBufferLocked(buffer);
368 image->mBuffer = nullptr;
369
370 bool found = false;
371 // cleanup acquired image list
372 for (auto it = mAcquiredImages.begin();
373 it != mAcquiredImages.end(); it++) {
374 AImage* readerCopy = *it;
375 if (readerCopy == image) {
376 found = true;
377 mAcquiredImages.erase(it);
378 break;
379 }
380 }
381 if (!found) {
382 ALOGE("Error: AImage %p is not generated by AImageReader %p",
383 image, this);
384 }
385}
386
387int
388AImageReader::getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
389 if (buffer == nullptr) return -1;
390
391 if (!buffer->crop.isEmpty()) {
392 return buffer->crop.getWidth();
393 }
394 return buffer->width;
395}
396
397int
398AImageReader::getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
399 if (buffer == nullptr) return -1;
400
401 if (!buffer->crop.isEmpty()) {
402 return buffer->crop.getHeight();
403 }
404 return buffer->height;
405}
406
407media_status_t
408AImageReader::acquireNextImage(/*out*/AImage** image) {
409 Mutex::Autolock _l(mLock);
410 return acquireCpuConsumerImageLocked(image);
411}
412
413media_status_t
414AImageReader::acquireLatestImage(/*out*/AImage** image) {
415 if (image == nullptr) {
416 return AMEDIA_ERROR_INVALID_PARAMETER;
417 }
418 Mutex::Autolock _l(mLock);
419 *image = nullptr;
420 AImage* prevImage = nullptr;
421 AImage* nextImage = nullptr;
422 media_status_t ret = acquireCpuConsumerImageLocked(&prevImage);
423 if (prevImage == nullptr) {
424 return ret;
425 }
426 for (;;) {
427 ret = acquireCpuConsumerImageLocked(&nextImage);
428 if (nextImage == nullptr) {
429 *image = prevImage;
430 return AMEDIA_OK;
431 }
432 prevImage->close();
433 prevImage->free();
434 prevImage = nextImage;
435 nextImage = nullptr;
436 }
437}
438
439EXPORT
440media_status_t AImageReader_new(
441 int32_t width, int32_t height, int32_t format, int32_t maxImages,
442 /*out*/AImageReader** reader) {
443 ALOGV("%s", __FUNCTION__);
444
445 if (width < 1 || height < 1) {
446 ALOGE("%s: image dimension must be positive: w:%d h:%d",
447 __FUNCTION__, width, height);
448 return AMEDIA_ERROR_INVALID_PARAMETER;
449 }
450
451 if (maxImages < 1) {
452 ALOGE("%s: max outstanding image count must be at least 1 (%d)",
453 __FUNCTION__, maxImages);
454 return AMEDIA_ERROR_INVALID_PARAMETER;
455 }
456
457 if (!AImageReader::isSupportedFormat(format)) {
458 ALOGE("%s: format %d is not supported by AImageReader",
459 __FUNCTION__, format);
460 return AMEDIA_ERROR_INVALID_PARAMETER;
461 }
462
463 if (reader == nullptr) {
464 ALOGE("%s: reader argument is null", __FUNCTION__);
465 return AMEDIA_ERROR_INVALID_PARAMETER;
466 }
467
468 //*reader = new AImageReader(width, height, format, maxImages);
469 AImageReader* tmpReader = new AImageReader(width, height, format, maxImages);
470 if (tmpReader == nullptr) {
471 ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
472 return AMEDIA_ERROR_UNKNOWN;
473 }
474 media_status_t ret = tmpReader->init();
475 if (ret != AMEDIA_OK) {
476 ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
477 delete tmpReader;
478 return ret;
479 }
480 *reader = tmpReader;
481 (*reader)->incStrong((void*) AImageReader_new);
482 return AMEDIA_OK;
483}
484
485EXPORT
486void AImageReader_delete(AImageReader* reader) {
487 ALOGV("%s", __FUNCTION__);
488 if (reader != nullptr) {
489 reader->decStrong((void*) AImageReader_delete);
490 }
491 return;
492}
493
494EXPORT
495media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
496 ALOGE("%s", __FUNCTION__);
497 if (reader == nullptr || window == nullptr) {
498 ALOGE("%s: invalid argument. reader %p, window %p",
499 __FUNCTION__, reader, window);
500 return AMEDIA_ERROR_INVALID_PARAMETER;
501 }
502 *window = reader->getWindow();
503 return AMEDIA_OK;
504}
505
506EXPORT
507media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
508 ALOGV("%s", __FUNCTION__);
509 if (reader == nullptr || width == nullptr) {
510 ALOGE("%s: invalid argument. reader %p, width %p",
511 __FUNCTION__, reader, width);
512 return AMEDIA_ERROR_INVALID_PARAMETER;
513 }
514 *width = reader->getWidth();
515 return AMEDIA_OK;
516}
517
518EXPORT
519media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
520 ALOGV("%s", __FUNCTION__);
521 if (reader == nullptr || height == nullptr) {
522 ALOGE("%s: invalid argument. reader %p, height %p",
523 __FUNCTION__, reader, height);
524 return AMEDIA_ERROR_INVALID_PARAMETER;
525 }
526 *height = reader->getHeight();
527 return AMEDIA_OK;
528}
529
530EXPORT
531media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
532 ALOGV("%s", __FUNCTION__);
533 if (reader == nullptr || format == nullptr) {
534 ALOGE("%s: invalid argument. reader %p, format %p",
535 __FUNCTION__, reader, format);
536 return AMEDIA_ERROR_INVALID_PARAMETER;
537 }
538 *format = reader->getFormat();
539 return AMEDIA_OK;
540}
541
542EXPORT
543media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
544 ALOGV("%s", __FUNCTION__);
545 if (reader == nullptr || maxImages == nullptr) {
546 ALOGE("%s: invalid argument. reader %p, maxImages %p",
547 __FUNCTION__, reader, maxImages);
548 return AMEDIA_ERROR_INVALID_PARAMETER;
549 }
550 *maxImages = reader->getMaxImages();
551 return AMEDIA_OK;
552}
553
554EXPORT
555media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
556 ALOGV("%s", __FUNCTION__);
557 if (reader == nullptr || image == nullptr) {
558 ALOGE("%s: invalid argument. reader %p, maxImages %p",
559 __FUNCTION__, reader, image);
560 return AMEDIA_ERROR_INVALID_PARAMETER;
561 }
562 return reader->acquireNextImage(image);
563}
564
565EXPORT
566media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
567 ALOGV("%s", __FUNCTION__);
568 if (reader == nullptr || image == nullptr) {
569 ALOGE("%s: invalid argument. reader %p, maxImages %p",
570 __FUNCTION__, reader, image);
571 return AMEDIA_ERROR_INVALID_PARAMETER;
572 }
573 return reader->acquireLatestImage(image);
574}
575
576EXPORT
577media_status_t AImageReader_setImageListener(
578 AImageReader* reader, AImageReader_ImageListener* listener) {
579 ALOGV("%s", __FUNCTION__);
Yin-Chia Yeh1d0955c2016-05-16 01:14:13 -0700580 if (reader == nullptr) {
581 ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800582 return AMEDIA_ERROR_INVALID_PARAMETER;
583 }
584
585 reader->setImageListener(listener);
586 return AMEDIA_OK;
587}