blob: c2093ace1a17a7fcfabae1218d268375a73e7ecb [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 "NdkImage"
21
22#include "NdkImagePriv.h"
23#include "NdkImageReaderPriv.h"
24
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080025#include <android_media_Utils.h>
Jooyung Hanfe304592019-02-21 15:12:59 +090026#include <private/android/AHardwareBufferHelpers.h>
Sally Qida6ca842022-01-10 16:10:28 -080027#include <ui/PublicFormat.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080028#include <utils/Log.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080029
30using namespace android;
31
32#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
33
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -070034AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage, BufferItem* buffer,
35 int64_t timestamp, int32_t width, int32_t height, int32_t numPlanes) :
36 mReader(reader), mFormat(format), mUsage(usage), mBuffer(buffer), mLockedBuffer(nullptr),
37 mTimestamp(timestamp), mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
Sally Qida6ca842022-01-10 16:10:28 -080038 PublicFormat publicFormat = static_cast<PublicFormat>(format);
39 mHalDataSpace = mapPublicFormatToHalDataspace(publicFormat);
Jayant Chowdhary9ddd6e82019-07-16 11:04:06 -070040 LOG_FATAL_IF(reader == nullptr, "AImageReader shouldn't be null while creating AImage");
Yin-Chia Yehc3603822016-01-18 22:11:19 -080041}
42
Yin-Chia Yehc3603822016-01-18 22:11:19 -080043AImage::~AImage() {
Yin-Chia Yeh41991982017-11-15 15:53:18 -080044 Mutex::Autolock _l(mLock);
Yin-Chia Yehc3603822016-01-18 22:11:19 -080045 if (!mIsClosed) {
46 LOG_ALWAYS_FATAL(
47 "Error: AImage %p is deleted before returning buffer to AImageReader!", this);
48 }
49}
50
51bool
52AImage::isClosed() const {
53 Mutex::Autolock _l(mLock);
54 return mIsClosed;
55}
56
57void
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080058AImage::close(int releaseFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -080059 Mutex::Autolock _l(mLock);
60 if (mIsClosed) {
61 return;
62 }
Jayant Chowdhary3a4af232020-12-15 11:01:03 -080063 if (mReader->mIsOpen) {
Jayant Chowdhary9ddd6e82019-07-16 11:04:06 -070064 mReader->releaseImageLocked(this, releaseFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -080065 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -080066 // Should have been set to nullptr in releaseImageLocked
67 // Set to nullptr here for extra safety only
68 mBuffer = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080069 mLockedBuffer = nullptr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080070 mIsClosed = true;
71}
72
73void
74AImage::free() {
75 if (!isClosed()) {
76 ALOGE("Cannot free AImage before close!");
77 return;
78 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -080079 delete this;
80}
81
82void
83AImage::lockReader() const {
Jayant Chowdhary9ddd6e82019-07-16 11:04:06 -070084 mReader->mLock.lock();
Yin-Chia Yehc3603822016-01-18 22:11:19 -080085}
86
87void
88AImage::unlockReader() const {
Jayant Chowdhary9ddd6e82019-07-16 11:04:06 -070089 mReader->mLock.unlock();
Yin-Chia Yehc3603822016-01-18 22:11:19 -080090}
91
92media_status_t
93AImage::getWidth(int32_t* width) const {
94 if (width == nullptr) {
95 return AMEDIA_ERROR_INVALID_PARAMETER;
96 }
97 *width = -1;
98 if (isClosed()) {
99 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
100 return AMEDIA_ERROR_INVALID_OBJECT;
101 }
102 *width = mWidth;
103 return AMEDIA_OK;
104}
105
106media_status_t
107AImage::getHeight(int32_t* height) const {
108 if (height == nullptr) {
109 return AMEDIA_ERROR_INVALID_PARAMETER;
110 }
111 *height = -1;
112 if (isClosed()) {
113 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
114 return AMEDIA_ERROR_INVALID_OBJECT;
115 }
116 *height = mHeight;
117 return AMEDIA_OK;
118}
119
120media_status_t
121AImage::getFormat(int32_t* format) const {
122 if (format == nullptr) {
123 return AMEDIA_ERROR_INVALID_PARAMETER;
124 }
125 *format = -1;
126 if (isClosed()) {
127 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
128 return AMEDIA_ERROR_INVALID_OBJECT;
129 }
130 *format = mFormat;
131 return AMEDIA_OK;
132}
133
134media_status_t
135AImage::getNumPlanes(int32_t* numPlanes) const {
136 if (numPlanes == nullptr) {
137 return AMEDIA_ERROR_INVALID_PARAMETER;
138 }
139 *numPlanes = -1;
140 if (isClosed()) {
141 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
142 return AMEDIA_ERROR_INVALID_OBJECT;
143 }
144 *numPlanes = mNumPlanes;
145 return AMEDIA_OK;
146}
147
148media_status_t
149AImage::getTimestamp(int64_t* timestamp) const {
150 if (timestamp == nullptr) {
151 return AMEDIA_ERROR_INVALID_PARAMETER;
152 }
153 *timestamp = -1;
154 if (isClosed()) {
155 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
156 return AMEDIA_ERROR_INVALID_OBJECT;
157 }
158 *timestamp = mTimestamp;
159 return AMEDIA_OK;
160}
161
Sally Qida6ca842022-01-10 16:10:28 -0800162media_status_t
163AImage::getDataSpace(android_dataspace* dataSpace) const {
164 if (dataSpace == nullptr) {
165 return AMEDIA_ERROR_INVALID_PARAMETER;
166 }
167 *dataSpace = static_cast<android_dataspace>(-1);
168 if (isClosed()) {
169 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
170 return AMEDIA_ERROR_INVALID_OBJECT;
171 }
172 *dataSpace = mHalDataSpace;
173 return AMEDIA_OK;
174}
175
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800176media_status_t AImage::lockImage() {
177 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
178 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
179 return AMEDIA_ERROR_INVALID_OBJECT;
180 }
181
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700182 if ((mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800183 ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700184 __FUNCTION__, this, mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800185 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
186 }
187
188 if (mLockedBuffer != nullptr) {
189 // Return immediately if the image has already been locked.
190 return AMEDIA_OK;
191 }
192
193 auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>();
194
Jooyung Hanfe304592019-02-21 15:12:59 +0900195 uint64_t grallocUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800196
197 status_t ret =
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700198 lockImageFromBuffer(mBuffer, grallocUsage, mBuffer->mFence->dup(), lockedBuffer.get());
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800199 if (ret != OK) {
200 ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret);
201 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
202 }
203
204 ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this);
205 mLockedBuffer = std::move(lockedBuffer);
206
207 return AMEDIA_OK;
208}
209
210media_status_t AImage::unlockImageIfLocked(int* fenceFd) {
211 if (fenceFd == nullptr) {
212 LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__);
213 return AMEDIA_ERROR_INVALID_PARAMETER;
214 }
215
216 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
217 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
218 return AMEDIA_ERROR_INVALID_OBJECT;
219 }
220
221 if (mLockedBuffer == nullptr) {
222 // This image hasn't been locked yet, no need to unlock.
223 *fenceFd = -1;
224 return AMEDIA_OK;
225 }
226
227 // No fence by default.
228 int releaseFenceFd = -1;
229 status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd);
230 if (res != OK) {
231 ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this);
232 *fenceFd = -1;
233 return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE;
234 }
235
236 *fenceFd = releaseFenceFd;
237 return AMEDIA_OK;
238}
239
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800240media_status_t
241AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800242 if (mLockedBuffer == nullptr) {
243 ALOGE("%s: buffer not locked.", __FUNCTION__);
244 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
245 }
246
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800247 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
248 ALOGE("Error: planeIdx %d out of bound [0,%d]",
249 planeIdx, mNumPlanes - 1);
250 return AMEDIA_ERROR_INVALID_PARAMETER;
251 }
252 if (pixelStride == nullptr) {
253 return AMEDIA_ERROR_INVALID_PARAMETER;
254 }
255 if (isClosed()) {
256 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
257 return AMEDIA_ERROR_INVALID_OBJECT;
258 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800259 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800260 switch (fmt) {
261 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800262 *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800263 return AMEDIA_OK;
264 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
265 *pixelStride = (planeIdx == 0) ? 1 : 2;
266 return AMEDIA_OK;
Emilian Peevdded00c2022-09-27 14:20:41 -0700267 case HAL_PIXEL_FORMAT_YCBCR_P010:
268 if (mLockedBuffer->dataCb && mLockedBuffer->dataCr) {
269 *pixelStride = (planeIdx == 0) ? 2 : mLockedBuffer->chromaStep;
270 } else {
271 *pixelStride = (planeIdx == 0) ? 2 : 4;
272 }
273 return AMEDIA_OK;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800274 case HAL_PIXEL_FORMAT_Y8:
275 *pixelStride = 1;
276 return AMEDIA_OK;
277 case HAL_PIXEL_FORMAT_YV12:
278 *pixelStride = 1;
279 return AMEDIA_OK;
280 case HAL_PIXEL_FORMAT_Y16:
281 case HAL_PIXEL_FORMAT_RAW16:
282 case HAL_PIXEL_FORMAT_RGB_565:
283 // Single plane 16bpp data.
284 *pixelStride = 2;
285 return AMEDIA_OK;
286 case HAL_PIXEL_FORMAT_RGBA_8888:
287 case HAL_PIXEL_FORMAT_RGBX_8888:
288 *pixelStride = 4;
289 return AMEDIA_OK;
290 case HAL_PIXEL_FORMAT_RGB_888:
291 // Single plane, 24bpp.
292 *pixelStride = 3;
293 return AMEDIA_OK;
294 case HAL_PIXEL_FORMAT_BLOB:
295 case HAL_PIXEL_FORMAT_RAW10:
296 case HAL_PIXEL_FORMAT_RAW12:
297 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
298 // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
299 // those are single plane data without pixel stride defined
300 return AMEDIA_ERROR_UNSUPPORTED;
301 default:
302 ALOGE("Pixel format: 0x%x is unsupported", fmt);
303 return AMEDIA_ERROR_UNSUPPORTED;
304 }
305}
306
307media_status_t
308AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800309 if (mLockedBuffer == nullptr) {
310 ALOGE("%s: buffer not locked.", __FUNCTION__);
311 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
312 }
313
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800314 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
315 ALOGE("Error: planeIdx %d out of bound [0,%d]",
316 planeIdx, mNumPlanes - 1);
317 return AMEDIA_ERROR_INVALID_PARAMETER;
318 }
319 if (rowStride == nullptr) {
320 return AMEDIA_ERROR_INVALID_PARAMETER;
321 }
322 if (isClosed()) {
323 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
324 return AMEDIA_ERROR_INVALID_OBJECT;
325 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800326 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800327 switch (fmt) {
328 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800329 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
330 : mLockedBuffer->chromaStride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800331 return AMEDIA_OK;
332 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800333 *rowStride = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800334 return AMEDIA_OK;
335 case HAL_PIXEL_FORMAT_YV12:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800336 if (mLockedBuffer->stride % 16) {
337 ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800338 return AMEDIA_ERROR_UNKNOWN;
339 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800340 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
341 : ALIGN(mLockedBuffer->stride / 2, 16);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800342 return AMEDIA_OK;
Emilian Peevdded00c2022-09-27 14:20:41 -0700343 case HAL_PIXEL_FORMAT_YCBCR_P010:
344 if (mLockedBuffer->dataCb && mLockedBuffer->dataCr) {
345 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride : mLockedBuffer->chromaStride;
346 } else {
347 *rowStride = mLockedBuffer->stride * 2;
348 }
349 return AMEDIA_OK;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800350 case HAL_PIXEL_FORMAT_RAW10:
351 case HAL_PIXEL_FORMAT_RAW12:
352 // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800353 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800354 return AMEDIA_OK;
355 case HAL_PIXEL_FORMAT_Y8:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800356 if (mLockedBuffer->stride % 16) {
357 ALOGE("Stride %d is not 16 pixel aligned!",
358 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800359 return AMEDIA_ERROR_UNKNOWN;
360 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800361 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800362 return AMEDIA_OK;
363 case HAL_PIXEL_FORMAT_Y16:
364 case HAL_PIXEL_FORMAT_RAW16:
365 // In native side, strides are specified in pixels, not in bytes.
366 // Single plane 16bpp bayer data. even width/height,
367 // row stride multiple of 16 pixels (32 bytes)
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800368 if (mLockedBuffer->stride % 16) {
369 ALOGE("Stride %d is not 16 pixel aligned!",
370 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800371 return AMEDIA_ERROR_UNKNOWN;
372 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800373 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800374 return AMEDIA_OK;
375 case HAL_PIXEL_FORMAT_RGB_565:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800376 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800377 return AMEDIA_OK;
378 case HAL_PIXEL_FORMAT_RGBA_8888:
379 case HAL_PIXEL_FORMAT_RGBX_8888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800380 *rowStride = mLockedBuffer->stride * 4;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800381 return AMEDIA_OK;
382 case HAL_PIXEL_FORMAT_RGB_888:
383 // Single plane, 24bpp.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800384 *rowStride = mLockedBuffer->stride * 3;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800385 return AMEDIA_OK;
386 case HAL_PIXEL_FORMAT_BLOB:
387 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
388 // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
389 // no row stride defined
390 return AMEDIA_ERROR_UNSUPPORTED;
391 default:
392 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
393 return AMEDIA_ERROR_UNSUPPORTED;
394 }
395}
396
397uint32_t
398AImage::getJpegSize() const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800399 if (mLockedBuffer == nullptr) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800400 LOG_ALWAYS_FATAL("Error: buffer is null");
401 }
402
403 uint32_t size = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800404 uint32_t width = mLockedBuffer->width;
405 uint8_t* jpegBuffer = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800406
407 // First check for JPEG transport header at the end of the buffer
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +0000408 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob_v2));
409 struct camera3_jpeg_blob_v2* blob = (struct camera3_jpeg_blob_v2*)(header);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800410 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
411 size = blob->jpeg_size;
412 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
413 }
414
415 // failed to find size, default to whole buffer
416 if (size == 0) {
417 /*
418 * This is a problem because not including the JPEG header
419 * means that in certain rare situations a regular JPEG blob
420 * will be misidentified as having a header, in which case
421 * we will get a garbage size value.
422 */
423 ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
424 __FUNCTION__, width);
425 size = width;
426 }
427
428 return size;
429}
430
431media_status_t
432AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800433 if (mLockedBuffer == nullptr) {
434 ALOGE("%s: buffer not locked.", __FUNCTION__);
435 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
436 }
437
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800438 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
439 ALOGE("Error: planeIdx %d out of bound [0,%d]",
440 planeIdx, mNumPlanes - 1);
441 return AMEDIA_ERROR_INVALID_PARAMETER;
442 }
443 if (data == nullptr || dataLength == nullptr) {
444 return AMEDIA_ERROR_INVALID_PARAMETER;
445 }
446 if (isClosed()) {
447 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
448 return AMEDIA_ERROR_INVALID_OBJECT;
449 }
450
451 uint32_t dataSize, ySize, cSize, cStride;
452 uint8_t* cb = nullptr;
453 uint8_t* cr = nullptr;
454 uint8_t* pData = nullptr;
455 int bytesPerPixel = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800456 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800457
458 switch (fmt) {
459 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800460 pData = (planeIdx == 0) ? mLockedBuffer->data
461 : (planeIdx == 1) ? mLockedBuffer->dataCb
462 : mLockedBuffer->dataCr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800463 // only map until last pixel
464 if (planeIdx == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800465 dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) +
466 mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800467 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800468 dataSize =
469 mLockedBuffer->chromaStride *
470 (mLockedBuffer->height / 2 - 1) +
471 mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) +
472 1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800473 }
474 break;
475 // NV21
476 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800477 cr = mLockedBuffer->data +
478 (mLockedBuffer->stride * mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800479 cb = cr + 1;
480 // only map until last pixel
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800481 ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) +
482 mLockedBuffer->width;
483 cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) +
484 mLockedBuffer->width - 1;
485 pData = (planeIdx == 0) ? mLockedBuffer->data
486 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800487 dataSize = (planeIdx == 0) ? ySize : cSize;
488 break;
489 case HAL_PIXEL_FORMAT_YV12:
490 // Y and C stride need to be 16 pixel aligned.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800491 if (mLockedBuffer->stride % 16) {
492 ALOGE("Stride %d is not 16 pixel aligned!",
493 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800494 return AMEDIA_ERROR_UNKNOWN;
495 }
496
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800497 ySize = mLockedBuffer->stride * mLockedBuffer->height;
498 cStride = ALIGN(mLockedBuffer->stride / 2, 16);
499 cr = mLockedBuffer->data + ySize;
500 cSize = cStride * mLockedBuffer->height / 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800501 cb = cr + cSize;
502
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800503 pData = (planeIdx == 0) ? mLockedBuffer->data
504 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800505 dataSize = (planeIdx == 0) ? ySize : cSize;
506 break;
Emilian Peevdded00c2022-09-27 14:20:41 -0700507 case HAL_PIXEL_FORMAT_YCBCR_P010:
508 if (mLockedBuffer->height % 2 != 0) {
509 ALOGE("YCBCR_P010: height (%d) should be a multiple of 2", mLockedBuffer->height);
510 return AMEDIA_ERROR_UNKNOWN;
511 }
512
513 if (mLockedBuffer->width <= 0) {
514 ALOGE("YCBCR_P010: width (%d) should be a > 0", mLockedBuffer->width);
515 return AMEDIA_ERROR_UNKNOWN;
516 }
517
518 if (mLockedBuffer->height <= 0) {
519 ALOGE("YCBCR_P010: height (%d) should be a > 0", mLockedBuffer->height);
520 return AMEDIA_ERROR_UNKNOWN;
521 }
522
523 if (mLockedBuffer->dataCb && mLockedBuffer->dataCr) {
524 pData = (planeIdx == 0) ? mLockedBuffer->data :
525 (planeIdx == 1) ? mLockedBuffer->dataCb : mLockedBuffer->dataCr;
526 // only map until last pixel
527 if (planeIdx == 0) {
528 cStride = mLockedBuffer->stride;
529 dataSize = cStride * (mLockedBuffer->height - 1) + mLockedBuffer->width * 2;
530 } else {
531 bytesPerPixel = mLockedBuffer->chromaStep;
532 cStride = mLockedBuffer->chromaStride;
533 dataSize = cStride * (mLockedBuffer->height / 2 - 1) +
534 bytesPerPixel * (mLockedBuffer->width / 2);
535 }
536 break;
537 }
538
539 cStride = mLockedBuffer->stride * 2;
540 ySize = cStride * mLockedBuffer->height;
541 cSize = ySize / 2;
542 cb = mLockedBuffer->data + ySize;
543 cr = cb + 2;
544
545 pData = (planeIdx == 0) ? mLockedBuffer->data : (planeIdx == 1) ? cb : cr;
546 dataSize = (planeIdx == 0) ? ySize : cSize;
547 break;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800548 case HAL_PIXEL_FORMAT_Y8:
549 // Single plane, 8bpp.
550
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800551 pData = mLockedBuffer->data;
552 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800553 break;
554 case HAL_PIXEL_FORMAT_Y16:
555 bytesPerPixel = 2;
556
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800557 pData = mLockedBuffer->data;
558 dataSize =
559 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800560 break;
561 case HAL_PIXEL_FORMAT_BLOB:
562 // Used for JPEG data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800563 if (mLockedBuffer->height != 1) {
564 ALOGE("Jpeg should have height value one but got %d",
565 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800566 return AMEDIA_ERROR_UNKNOWN;
567 }
568
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800569 pData = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800570 dataSize = getJpegSize();
571 break;
572 case HAL_PIXEL_FORMAT_RAW16:
573 // Single plane 16bpp bayer data.
574 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800575 pData = mLockedBuffer->data;
576 dataSize =
577 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800578 break;
579 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
580 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800581 if (mLockedBuffer->height != 1) {
582 ALOGE("RAW_OPAQUE should have height value one but got %d",
583 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800584 return AMEDIA_ERROR_UNKNOWN;
585 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800586 pData = mLockedBuffer->data;
587 dataSize = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800588 break;
589 case HAL_PIXEL_FORMAT_RAW10:
590 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800591 if (mLockedBuffer->width % 4) {
592 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800593 return AMEDIA_ERROR_UNKNOWN;
594 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800595 if (mLockedBuffer->height % 2) {
596 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800597 return AMEDIA_ERROR_UNKNOWN;
598 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800599 if (mLockedBuffer->stride < (mLockedBuffer->width * 10 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800600 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800601 mLockedBuffer->stride, mLockedBuffer->width * 10 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800602 return AMEDIA_ERROR_UNKNOWN;
603 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800604 pData = mLockedBuffer->data;
605 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800606 break;
607 case HAL_PIXEL_FORMAT_RAW12:
608 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800609 if (mLockedBuffer->width % 4) {
610 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800611 return AMEDIA_ERROR_UNKNOWN;
612 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800613 if (mLockedBuffer->height % 2) {
614 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800615 return AMEDIA_ERROR_UNKNOWN;
616 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800617 if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800618 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800619 mLockedBuffer->stride, mLockedBuffer->width * 12 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800620 return AMEDIA_ERROR_UNKNOWN;
621 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800622 pData = mLockedBuffer->data;
623 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800624 break;
625 case HAL_PIXEL_FORMAT_RGBA_8888:
626 case HAL_PIXEL_FORMAT_RGBX_8888:
627 // Single plane, 32bpp.
628 bytesPerPixel = 4;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800629 pData = mLockedBuffer->data;
630 dataSize =
631 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800632 break;
633 case HAL_PIXEL_FORMAT_RGB_565:
634 // Single plane, 16bpp.
635 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800636 pData = mLockedBuffer->data;
637 dataSize =
638 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800639 break;
640 case HAL_PIXEL_FORMAT_RGB_888:
641 // Single plane, 24bpp.
642 bytesPerPixel = 3;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800643 pData = mLockedBuffer->data;
644 dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800645 break;
646 default:
647 ALOGE("Pixel format: 0x%x is unsupported", fmt);
648 return AMEDIA_ERROR_UNSUPPORTED;
649 }
650
651 *data = pData;
652 *dataLength = dataSize;
653 return AMEDIA_OK;
654}
655
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800656media_status_t
657AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const {
658 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
659 ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this);
660 return AMEDIA_ERROR_INVALID_OBJECT;
661 }
662
663 // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast.
664 *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get());
665 return AMEDIA_OK;
666}
667
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800668EXPORT
669void AImage_delete(AImage* image) {
670 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800671 AImage_deleteAsync(image, -1);
672 return;
673}
674
675EXPORT
676void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
677 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800678 if (image != nullptr) {
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800679 image->lockReader();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800680 image->close(releaseFenceFd);
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800681 image->unlockReader();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800682 if (!image->isClosed()) {
683 LOG_ALWAYS_FATAL("Image close failed!");
684 }
685 image->free();
686 }
687 return;
688}
689
690EXPORT
691media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
692 ALOGV("%s", __FUNCTION__);
693 if (image == nullptr || width == nullptr) {
694 ALOGE("%s: bad argument. image %p width %p",
695 __FUNCTION__, image, width);
696 return AMEDIA_ERROR_INVALID_PARAMETER;
697 }
698 return image->getWidth(width);
699}
700
701EXPORT
702media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
703 ALOGV("%s", __FUNCTION__);
704 if (image == nullptr || height == nullptr) {
705 ALOGE("%s: bad argument. image %p height %p",
706 __FUNCTION__, image, height);
707 return AMEDIA_ERROR_INVALID_PARAMETER;
708 }
709 return image->getHeight(height);
710}
711
712EXPORT
713media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
714 ALOGV("%s", __FUNCTION__);
715 if (image == nullptr || format == nullptr) {
716 ALOGE("%s: bad argument. image %p format %p",
717 __FUNCTION__, image, format);
718 return AMEDIA_ERROR_INVALID_PARAMETER;
719 }
720 return image->getFormat(format);
721}
722
723EXPORT
724media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
725 ALOGV("%s", __FUNCTION__);
726 if (image == nullptr || rect == nullptr) {
727 ALOGE("%s: bad argument. image %p rect %p",
728 __FUNCTION__, image, rect);
729 return AMEDIA_ERROR_INVALID_PARAMETER;
730 }
731 // For now AImage only supports camera outputs where cropRect is always full window
732 int32_t width = -1;
733 media_status_t ret = image->getWidth(&width);
734 if (ret != AMEDIA_OK) {
735 return ret;
736 }
737 int32_t height = -1;
738 ret = image->getHeight(&height);
739 if (ret != AMEDIA_OK) {
740 return ret;
741 }
742 rect->left = 0;
743 rect->top = 0;
744 rect->right = width;
745 rect->bottom = height;
746 return AMEDIA_OK;
747}
748
749EXPORT
750media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
751 ALOGV("%s", __FUNCTION__);
752 if (image == nullptr || timestampNs == nullptr) {
753 ALOGE("%s: bad argument. image %p timestampNs %p",
754 __FUNCTION__, image, timestampNs);
755 return AMEDIA_ERROR_INVALID_PARAMETER;
756 }
757 return image->getTimestamp(timestampNs);
758}
759
760EXPORT
761media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
762 ALOGV("%s", __FUNCTION__);
763 if (image == nullptr || numPlanes == nullptr) {
764 ALOGE("%s: bad argument. image %p numPlanes %p",
765 __FUNCTION__, image, numPlanes);
766 return AMEDIA_ERROR_INVALID_PARAMETER;
767 }
768 return image->getNumPlanes(numPlanes);
769}
770
771EXPORT
772media_status_t AImage_getPlanePixelStride(
773 const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
774 ALOGV("%s", __FUNCTION__);
775 if (image == nullptr || pixelStride == nullptr) {
776 ALOGE("%s: bad argument. image %p pixelStride %p",
777 __FUNCTION__, image, pixelStride);
778 return AMEDIA_ERROR_INVALID_PARAMETER;
779 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800780 media_status_t ret = const_cast<AImage*>(image)->lockImage();
781 if (ret != AMEDIA_OK) {
782 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
783 __FUNCTION__, image, ret);
784 return ret;
785 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800786 return image->getPlanePixelStride(planeIdx, pixelStride);
787}
788
789EXPORT
790media_status_t AImage_getPlaneRowStride(
791 const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
792 ALOGV("%s", __FUNCTION__);
793 if (image == nullptr || rowStride == nullptr) {
794 ALOGE("%s: bad argument. image %p rowStride %p",
795 __FUNCTION__, image, rowStride);
796 return AMEDIA_ERROR_INVALID_PARAMETER;
797 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800798 media_status_t ret = const_cast<AImage*>(image)->lockImage();
799 if (ret != AMEDIA_OK) {
800 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
801 __FUNCTION__, image, ret);
802 return ret;
803 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800804 return image->getPlaneRowStride(planeIdx, rowStride);
805}
806
807EXPORT
808media_status_t AImage_getPlaneData(
809 const AImage* image, int planeIdx,
810 /*out*/uint8_t** data, /*out*/int* dataLength) {
811 ALOGV("%s", __FUNCTION__);
812 if (image == nullptr || data == nullptr || dataLength == nullptr) {
813 ALOGE("%s: bad argument. image %p data %p dataLength %p",
814 __FUNCTION__, image, data, dataLength);
815 return AMEDIA_ERROR_INVALID_PARAMETER;
816 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800817 media_status_t ret = const_cast<AImage*>(image)->lockImage();
818 if (ret != AMEDIA_OK) {
819 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
820 __FUNCTION__, image, ret);
821 return ret;
822 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800823 return image->getPlaneData(planeIdx, data, dataLength);
824}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800825
826EXPORT
827media_status_t AImage_getHardwareBuffer(
828 const AImage* image, /*out*/AHardwareBuffer** buffer) {
829 ALOGV("%s", __FUNCTION__);
830
831 if (image == nullptr || buffer == nullptr) {
832 ALOGE("%s: bad argument. image %p buffer %p", __FUNCTION__, image, buffer);
833 return AMEDIA_ERROR_INVALID_PARAMETER;
834 }
835 return image->getHardwareBuffer(buffer);
836}
Sally Qida6ca842022-01-10 16:10:28 -0800837
838EXPORT
839media_status_t AImage_getDataSpace(
840 const AImage* image, /*out*/int32_t* dataSpace) {
841 ALOGV("%s", __FUNCTION__);
842
843 if (image == nullptr || dataSpace == nullptr) {
844 ALOGE("%s: bad argument. image %p dataSpace %p", __FUNCTION__, image, dataSpace);
845 return AMEDIA_ERROR_INVALID_PARAMETER;
846 }
847 return image->getDataSpace((android_dataspace*)(dataSpace));
848}