blob: 12a0d53f7cda96be62111d621c0b3519f3fdb70d [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>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080027#include <utils/Log.h>
Yin-Chia Yehc3603822016-01-18 22:11:19 -080028
29using namespace android;
30
31#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
32
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -070033AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage, BufferItem* buffer,
34 int64_t timestamp, int32_t width, int32_t height, int32_t numPlanes) :
35 mReader(reader), mFormat(format), mUsage(usage), mBuffer(buffer), mLockedBuffer(nullptr),
36 mTimestamp(timestamp), mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
Jayant Chowdhary9ddd6e82019-07-16 11:04:06 -070037 LOG_FATAL_IF(reader == nullptr, "AImageReader shouldn't be null while creating AImage");
Yin-Chia Yehc3603822016-01-18 22:11:19 -080038}
39
Yin-Chia Yehc3603822016-01-18 22:11:19 -080040AImage::~AImage() {
Yin-Chia Yeh41991982017-11-15 15:53:18 -080041 Mutex::Autolock _l(mLock);
Yin-Chia Yehc3603822016-01-18 22:11:19 -080042 if (!mIsClosed) {
43 LOG_ALWAYS_FATAL(
44 "Error: AImage %p is deleted before returning buffer to AImageReader!", this);
45 }
46}
47
48bool
49AImage::isClosed() const {
50 Mutex::Autolock _l(mLock);
51 return mIsClosed;
52}
53
54void
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080055AImage::close(int releaseFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -080056 Mutex::Autolock _l(mLock);
57 if (mIsClosed) {
58 return;
59 }
Jayant Chowdhary3a4af232020-12-15 11:01:03 -080060 if (mReader->mIsOpen) {
Jayant Chowdhary9ddd6e82019-07-16 11:04:06 -070061 mReader->releaseImageLocked(this, releaseFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -080062 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -080063 // Should have been set to nullptr in releaseImageLocked
64 // Set to nullptr here for extra safety only
65 mBuffer = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080066 mLockedBuffer = nullptr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080067 mIsClosed = true;
68}
69
70void
71AImage::free() {
72 if (!isClosed()) {
73 ALOGE("Cannot free AImage before close!");
74 return;
75 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -080076 delete this;
77}
78
79void
80AImage::lockReader() const {
Jayant Chowdhary9ddd6e82019-07-16 11:04:06 -070081 mReader->mLock.lock();
Yin-Chia Yehc3603822016-01-18 22:11:19 -080082}
83
84void
85AImage::unlockReader() const {
Jayant Chowdhary9ddd6e82019-07-16 11:04:06 -070086 mReader->mLock.unlock();
Yin-Chia Yehc3603822016-01-18 22:11:19 -080087}
88
89media_status_t
90AImage::getWidth(int32_t* width) const {
91 if (width == nullptr) {
92 return AMEDIA_ERROR_INVALID_PARAMETER;
93 }
94 *width = -1;
95 if (isClosed()) {
96 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
97 return AMEDIA_ERROR_INVALID_OBJECT;
98 }
99 *width = mWidth;
100 return AMEDIA_OK;
101}
102
103media_status_t
104AImage::getHeight(int32_t* height) const {
105 if (height == nullptr) {
106 return AMEDIA_ERROR_INVALID_PARAMETER;
107 }
108 *height = -1;
109 if (isClosed()) {
110 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
111 return AMEDIA_ERROR_INVALID_OBJECT;
112 }
113 *height = mHeight;
114 return AMEDIA_OK;
115}
116
117media_status_t
118AImage::getFormat(int32_t* format) const {
119 if (format == nullptr) {
120 return AMEDIA_ERROR_INVALID_PARAMETER;
121 }
122 *format = -1;
123 if (isClosed()) {
124 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
125 return AMEDIA_ERROR_INVALID_OBJECT;
126 }
127 *format = mFormat;
128 return AMEDIA_OK;
129}
130
131media_status_t
132AImage::getNumPlanes(int32_t* numPlanes) const {
133 if (numPlanes == nullptr) {
134 return AMEDIA_ERROR_INVALID_PARAMETER;
135 }
136 *numPlanes = -1;
137 if (isClosed()) {
138 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
139 return AMEDIA_ERROR_INVALID_OBJECT;
140 }
141 *numPlanes = mNumPlanes;
142 return AMEDIA_OK;
143}
144
145media_status_t
146AImage::getTimestamp(int64_t* timestamp) const {
147 if (timestamp == nullptr) {
148 return AMEDIA_ERROR_INVALID_PARAMETER;
149 }
150 *timestamp = -1;
151 if (isClosed()) {
152 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
153 return AMEDIA_ERROR_INVALID_OBJECT;
154 }
155 *timestamp = mTimestamp;
156 return AMEDIA_OK;
157}
158
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800159media_status_t AImage::lockImage() {
160 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
161 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
162 return AMEDIA_ERROR_INVALID_OBJECT;
163 }
164
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700165 if ((mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800166 ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700167 __FUNCTION__, this, mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800168 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
169 }
170
171 if (mLockedBuffer != nullptr) {
172 // Return immediately if the image has already been locked.
173 return AMEDIA_OK;
174 }
175
176 auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>();
177
Jooyung Hanfe304592019-02-21 15:12:59 +0900178 uint64_t grallocUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800179
180 status_t ret =
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700181 lockImageFromBuffer(mBuffer, grallocUsage, mBuffer->mFence->dup(), lockedBuffer.get());
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800182 if (ret != OK) {
183 ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret);
184 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
185 }
186
187 ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this);
188 mLockedBuffer = std::move(lockedBuffer);
189
190 return AMEDIA_OK;
191}
192
193media_status_t AImage::unlockImageIfLocked(int* fenceFd) {
194 if (fenceFd == nullptr) {
195 LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__);
196 return AMEDIA_ERROR_INVALID_PARAMETER;
197 }
198
199 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
200 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
201 return AMEDIA_ERROR_INVALID_OBJECT;
202 }
203
204 if (mLockedBuffer == nullptr) {
205 // This image hasn't been locked yet, no need to unlock.
206 *fenceFd = -1;
207 return AMEDIA_OK;
208 }
209
210 // No fence by default.
211 int releaseFenceFd = -1;
212 status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd);
213 if (res != OK) {
214 ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this);
215 *fenceFd = -1;
216 return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE;
217 }
218
219 *fenceFd = releaseFenceFd;
220 return AMEDIA_OK;
221}
222
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800223media_status_t
224AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800225 if (mLockedBuffer == nullptr) {
226 ALOGE("%s: buffer not locked.", __FUNCTION__);
227 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
228 }
229
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800230 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
231 ALOGE("Error: planeIdx %d out of bound [0,%d]",
232 planeIdx, mNumPlanes - 1);
233 return AMEDIA_ERROR_INVALID_PARAMETER;
234 }
235 if (pixelStride == nullptr) {
236 return AMEDIA_ERROR_INVALID_PARAMETER;
237 }
238 if (isClosed()) {
239 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
240 return AMEDIA_ERROR_INVALID_OBJECT;
241 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800242 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800243 switch (fmt) {
244 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800245 *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800246 return AMEDIA_OK;
247 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
248 *pixelStride = (planeIdx == 0) ? 1 : 2;
249 return AMEDIA_OK;
250 case HAL_PIXEL_FORMAT_Y8:
251 *pixelStride = 1;
252 return AMEDIA_OK;
253 case HAL_PIXEL_FORMAT_YV12:
254 *pixelStride = 1;
255 return AMEDIA_OK;
256 case HAL_PIXEL_FORMAT_Y16:
257 case HAL_PIXEL_FORMAT_RAW16:
258 case HAL_PIXEL_FORMAT_RGB_565:
259 // Single plane 16bpp data.
260 *pixelStride = 2;
261 return AMEDIA_OK;
262 case HAL_PIXEL_FORMAT_RGBA_8888:
263 case HAL_PIXEL_FORMAT_RGBX_8888:
264 *pixelStride = 4;
265 return AMEDIA_OK;
266 case HAL_PIXEL_FORMAT_RGB_888:
267 // Single plane, 24bpp.
268 *pixelStride = 3;
269 return AMEDIA_OK;
270 case HAL_PIXEL_FORMAT_BLOB:
271 case HAL_PIXEL_FORMAT_RAW10:
272 case HAL_PIXEL_FORMAT_RAW12:
273 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
274 // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
275 // those are single plane data without pixel stride defined
276 return AMEDIA_ERROR_UNSUPPORTED;
277 default:
278 ALOGE("Pixel format: 0x%x is unsupported", fmt);
279 return AMEDIA_ERROR_UNSUPPORTED;
280 }
281}
282
283media_status_t
284AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800285 if (mLockedBuffer == nullptr) {
286 ALOGE("%s: buffer not locked.", __FUNCTION__);
287 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
288 }
289
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800290 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
291 ALOGE("Error: planeIdx %d out of bound [0,%d]",
292 planeIdx, mNumPlanes - 1);
293 return AMEDIA_ERROR_INVALID_PARAMETER;
294 }
295 if (rowStride == nullptr) {
296 return AMEDIA_ERROR_INVALID_PARAMETER;
297 }
298 if (isClosed()) {
299 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
300 return AMEDIA_ERROR_INVALID_OBJECT;
301 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800302 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800303 switch (fmt) {
304 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800305 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
306 : mLockedBuffer->chromaStride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800307 return AMEDIA_OK;
308 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800309 *rowStride = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800310 return AMEDIA_OK;
311 case HAL_PIXEL_FORMAT_YV12:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800312 if (mLockedBuffer->stride % 16) {
313 ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800314 return AMEDIA_ERROR_UNKNOWN;
315 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800316 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
317 : ALIGN(mLockedBuffer->stride / 2, 16);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800318 return AMEDIA_OK;
319 case HAL_PIXEL_FORMAT_RAW10:
320 case HAL_PIXEL_FORMAT_RAW12:
321 // 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 -0800322 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800323 return AMEDIA_OK;
324 case HAL_PIXEL_FORMAT_Y8:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800325 if (mLockedBuffer->stride % 16) {
326 ALOGE("Stride %d is not 16 pixel aligned!",
327 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800328 return AMEDIA_ERROR_UNKNOWN;
329 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800330 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800331 return AMEDIA_OK;
332 case HAL_PIXEL_FORMAT_Y16:
333 case HAL_PIXEL_FORMAT_RAW16:
334 // In native side, strides are specified in pixels, not in bytes.
335 // Single plane 16bpp bayer data. even width/height,
336 // row stride multiple of 16 pixels (32 bytes)
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800337 if (mLockedBuffer->stride % 16) {
338 ALOGE("Stride %d is not 16 pixel aligned!",
339 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800340 return AMEDIA_ERROR_UNKNOWN;
341 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800342 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800343 return AMEDIA_OK;
344 case HAL_PIXEL_FORMAT_RGB_565:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800345 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800346 return AMEDIA_OK;
347 case HAL_PIXEL_FORMAT_RGBA_8888:
348 case HAL_PIXEL_FORMAT_RGBX_8888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800349 *rowStride = mLockedBuffer->stride * 4;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800350 return AMEDIA_OK;
351 case HAL_PIXEL_FORMAT_RGB_888:
352 // Single plane, 24bpp.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800353 *rowStride = mLockedBuffer->stride * 3;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800354 return AMEDIA_OK;
355 case HAL_PIXEL_FORMAT_BLOB:
356 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
357 // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
358 // no row stride defined
359 return AMEDIA_ERROR_UNSUPPORTED;
360 default:
361 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
362 return AMEDIA_ERROR_UNSUPPORTED;
363 }
364}
365
366uint32_t
367AImage::getJpegSize() const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800368 if (mLockedBuffer == nullptr) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800369 LOG_ALWAYS_FATAL("Error: buffer is null");
370 }
371
372 uint32_t size = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800373 uint32_t width = mLockedBuffer->width;
374 uint8_t* jpegBuffer = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800375
376 // First check for JPEG transport header at the end of the buffer
Jayant Chowdharyc67af1b2022-04-07 18:05:04 +0000377 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob_v2));
378 struct camera3_jpeg_blob_v2* blob = (struct camera3_jpeg_blob_v2*)(header);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800379 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
380 size = blob->jpeg_size;
381 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
382 }
383
384 // failed to find size, default to whole buffer
385 if (size == 0) {
386 /*
387 * This is a problem because not including the JPEG header
388 * means that in certain rare situations a regular JPEG blob
389 * will be misidentified as having a header, in which case
390 * we will get a garbage size value.
391 */
392 ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
393 __FUNCTION__, width);
394 size = width;
395 }
396
397 return size;
398}
399
400media_status_t
401AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800402 if (mLockedBuffer == nullptr) {
403 ALOGE("%s: buffer not locked.", __FUNCTION__);
404 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
405 }
406
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800407 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
408 ALOGE("Error: planeIdx %d out of bound [0,%d]",
409 planeIdx, mNumPlanes - 1);
410 return AMEDIA_ERROR_INVALID_PARAMETER;
411 }
412 if (data == nullptr || dataLength == nullptr) {
413 return AMEDIA_ERROR_INVALID_PARAMETER;
414 }
415 if (isClosed()) {
416 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
417 return AMEDIA_ERROR_INVALID_OBJECT;
418 }
419
420 uint32_t dataSize, ySize, cSize, cStride;
421 uint8_t* cb = nullptr;
422 uint8_t* cr = nullptr;
423 uint8_t* pData = nullptr;
424 int bytesPerPixel = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800425 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800426
427 switch (fmt) {
428 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800429 pData = (planeIdx == 0) ? mLockedBuffer->data
430 : (planeIdx == 1) ? mLockedBuffer->dataCb
431 : mLockedBuffer->dataCr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800432 // only map until last pixel
433 if (planeIdx == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800434 dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) +
435 mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800436 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800437 dataSize =
438 mLockedBuffer->chromaStride *
439 (mLockedBuffer->height / 2 - 1) +
440 mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) +
441 1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800442 }
443 break;
444 // NV21
445 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800446 cr = mLockedBuffer->data +
447 (mLockedBuffer->stride * mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800448 cb = cr + 1;
449 // only map until last pixel
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800450 ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) +
451 mLockedBuffer->width;
452 cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) +
453 mLockedBuffer->width - 1;
454 pData = (planeIdx == 0) ? mLockedBuffer->data
455 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800456 dataSize = (planeIdx == 0) ? ySize : cSize;
457 break;
458 case HAL_PIXEL_FORMAT_YV12:
459 // Y and C stride need to be 16 pixel aligned.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800460 if (mLockedBuffer->stride % 16) {
461 ALOGE("Stride %d is not 16 pixel aligned!",
462 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800463 return AMEDIA_ERROR_UNKNOWN;
464 }
465
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800466 ySize = mLockedBuffer->stride * mLockedBuffer->height;
467 cStride = ALIGN(mLockedBuffer->stride / 2, 16);
468 cr = mLockedBuffer->data + ySize;
469 cSize = cStride * mLockedBuffer->height / 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800470 cb = cr + cSize;
471
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800472 pData = (planeIdx == 0) ? mLockedBuffer->data
473 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800474 dataSize = (planeIdx == 0) ? ySize : cSize;
475 break;
476 case HAL_PIXEL_FORMAT_Y8:
477 // Single plane, 8bpp.
478
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800479 pData = mLockedBuffer->data;
480 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800481 break;
482 case HAL_PIXEL_FORMAT_Y16:
483 bytesPerPixel = 2;
484
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800485 pData = mLockedBuffer->data;
486 dataSize =
487 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800488 break;
489 case HAL_PIXEL_FORMAT_BLOB:
490 // Used for JPEG data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800491 if (mLockedBuffer->height != 1) {
492 ALOGE("Jpeg should have height value one but got %d",
493 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800494 return AMEDIA_ERROR_UNKNOWN;
495 }
496
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800497 pData = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800498 dataSize = getJpegSize();
499 break;
500 case HAL_PIXEL_FORMAT_RAW16:
501 // Single plane 16bpp bayer data.
502 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800503 pData = mLockedBuffer->data;
504 dataSize =
505 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800506 break;
507 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
508 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800509 if (mLockedBuffer->height != 1) {
510 ALOGE("RAW_OPAQUE should have height value one but got %d",
511 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800512 return AMEDIA_ERROR_UNKNOWN;
513 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800514 pData = mLockedBuffer->data;
515 dataSize = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800516 break;
517 case HAL_PIXEL_FORMAT_RAW10:
518 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800519 if (mLockedBuffer->width % 4) {
520 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800521 return AMEDIA_ERROR_UNKNOWN;
522 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800523 if (mLockedBuffer->height % 2) {
524 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800525 return AMEDIA_ERROR_UNKNOWN;
526 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800527 if (mLockedBuffer->stride < (mLockedBuffer->width * 10 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800528 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800529 mLockedBuffer->stride, mLockedBuffer->width * 10 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800530 return AMEDIA_ERROR_UNKNOWN;
531 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800532 pData = mLockedBuffer->data;
533 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800534 break;
535 case HAL_PIXEL_FORMAT_RAW12:
536 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800537 if (mLockedBuffer->width % 4) {
538 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800539 return AMEDIA_ERROR_UNKNOWN;
540 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800541 if (mLockedBuffer->height % 2) {
542 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800543 return AMEDIA_ERROR_UNKNOWN;
544 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800545 if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800546 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800547 mLockedBuffer->stride, mLockedBuffer->width * 12 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800548 return AMEDIA_ERROR_UNKNOWN;
549 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800550 pData = mLockedBuffer->data;
551 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800552 break;
553 case HAL_PIXEL_FORMAT_RGBA_8888:
554 case HAL_PIXEL_FORMAT_RGBX_8888:
555 // Single plane, 32bpp.
556 bytesPerPixel = 4;
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_RGB_565:
562 // Single plane, 16bpp.
563 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800564 pData = mLockedBuffer->data;
565 dataSize =
566 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800567 break;
568 case HAL_PIXEL_FORMAT_RGB_888:
569 // Single plane, 24bpp.
570 bytesPerPixel = 3;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800571 pData = mLockedBuffer->data;
572 dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800573 break;
574 default:
575 ALOGE("Pixel format: 0x%x is unsupported", fmt);
576 return AMEDIA_ERROR_UNSUPPORTED;
577 }
578
579 *data = pData;
580 *dataLength = dataSize;
581 return AMEDIA_OK;
582}
583
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800584media_status_t
585AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const {
586 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
587 ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this);
588 return AMEDIA_ERROR_INVALID_OBJECT;
589 }
590
591 // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast.
592 *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get());
593 return AMEDIA_OK;
594}
595
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800596EXPORT
597void AImage_delete(AImage* image) {
598 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800599 AImage_deleteAsync(image, -1);
600 return;
601}
602
603EXPORT
604void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
605 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800606 if (image != nullptr) {
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800607 image->lockReader();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800608 image->close(releaseFenceFd);
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800609 image->unlockReader();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800610 if (!image->isClosed()) {
611 LOG_ALWAYS_FATAL("Image close failed!");
612 }
613 image->free();
614 }
615 return;
616}
617
618EXPORT
619media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
620 ALOGV("%s", __FUNCTION__);
621 if (image == nullptr || width == nullptr) {
622 ALOGE("%s: bad argument. image %p width %p",
623 __FUNCTION__, image, width);
624 return AMEDIA_ERROR_INVALID_PARAMETER;
625 }
626 return image->getWidth(width);
627}
628
629EXPORT
630media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
631 ALOGV("%s", __FUNCTION__);
632 if (image == nullptr || height == nullptr) {
633 ALOGE("%s: bad argument. image %p height %p",
634 __FUNCTION__, image, height);
635 return AMEDIA_ERROR_INVALID_PARAMETER;
636 }
637 return image->getHeight(height);
638}
639
640EXPORT
641media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
642 ALOGV("%s", __FUNCTION__);
643 if (image == nullptr || format == nullptr) {
644 ALOGE("%s: bad argument. image %p format %p",
645 __FUNCTION__, image, format);
646 return AMEDIA_ERROR_INVALID_PARAMETER;
647 }
648 return image->getFormat(format);
649}
650
651EXPORT
652media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
653 ALOGV("%s", __FUNCTION__);
654 if (image == nullptr || rect == nullptr) {
655 ALOGE("%s: bad argument. image %p rect %p",
656 __FUNCTION__, image, rect);
657 return AMEDIA_ERROR_INVALID_PARAMETER;
658 }
659 // For now AImage only supports camera outputs where cropRect is always full window
660 int32_t width = -1;
661 media_status_t ret = image->getWidth(&width);
662 if (ret != AMEDIA_OK) {
663 return ret;
664 }
665 int32_t height = -1;
666 ret = image->getHeight(&height);
667 if (ret != AMEDIA_OK) {
668 return ret;
669 }
670 rect->left = 0;
671 rect->top = 0;
672 rect->right = width;
673 rect->bottom = height;
674 return AMEDIA_OK;
675}
676
677EXPORT
678media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
679 ALOGV("%s", __FUNCTION__);
680 if (image == nullptr || timestampNs == nullptr) {
681 ALOGE("%s: bad argument. image %p timestampNs %p",
682 __FUNCTION__, image, timestampNs);
683 return AMEDIA_ERROR_INVALID_PARAMETER;
684 }
685 return image->getTimestamp(timestampNs);
686}
687
688EXPORT
689media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
690 ALOGV("%s", __FUNCTION__);
691 if (image == nullptr || numPlanes == nullptr) {
692 ALOGE("%s: bad argument. image %p numPlanes %p",
693 __FUNCTION__, image, numPlanes);
694 return AMEDIA_ERROR_INVALID_PARAMETER;
695 }
696 return image->getNumPlanes(numPlanes);
697}
698
699EXPORT
700media_status_t AImage_getPlanePixelStride(
701 const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
702 ALOGV("%s", __FUNCTION__);
703 if (image == nullptr || pixelStride == nullptr) {
704 ALOGE("%s: bad argument. image %p pixelStride %p",
705 __FUNCTION__, image, pixelStride);
706 return AMEDIA_ERROR_INVALID_PARAMETER;
707 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800708 media_status_t ret = const_cast<AImage*>(image)->lockImage();
709 if (ret != AMEDIA_OK) {
710 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
711 __FUNCTION__, image, ret);
712 return ret;
713 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800714 return image->getPlanePixelStride(planeIdx, pixelStride);
715}
716
717EXPORT
718media_status_t AImage_getPlaneRowStride(
719 const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
720 ALOGV("%s", __FUNCTION__);
721 if (image == nullptr || rowStride == nullptr) {
722 ALOGE("%s: bad argument. image %p rowStride %p",
723 __FUNCTION__, image, rowStride);
724 return AMEDIA_ERROR_INVALID_PARAMETER;
725 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800726 media_status_t ret = const_cast<AImage*>(image)->lockImage();
727 if (ret != AMEDIA_OK) {
728 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
729 __FUNCTION__, image, ret);
730 return ret;
731 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800732 return image->getPlaneRowStride(planeIdx, rowStride);
733}
734
735EXPORT
736media_status_t AImage_getPlaneData(
737 const AImage* image, int planeIdx,
738 /*out*/uint8_t** data, /*out*/int* dataLength) {
739 ALOGV("%s", __FUNCTION__);
740 if (image == nullptr || data == nullptr || dataLength == nullptr) {
741 ALOGE("%s: bad argument. image %p data %p dataLength %p",
742 __FUNCTION__, image, data, dataLength);
743 return AMEDIA_ERROR_INVALID_PARAMETER;
744 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800745 media_status_t ret = const_cast<AImage*>(image)->lockImage();
746 if (ret != AMEDIA_OK) {
747 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
748 __FUNCTION__, image, ret);
749 return ret;
750 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800751 return image->getPlaneData(planeIdx, data, dataLength);
752}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800753
754EXPORT
755media_status_t AImage_getHardwareBuffer(
756 const AImage* image, /*out*/AHardwareBuffer** buffer) {
757 ALOGV("%s", __FUNCTION__);
758
759 if (image == nullptr || buffer == nullptr) {
760 ALOGE("%s: bad argument. image %p buffer %p", __FUNCTION__, image, buffer);
761 return AMEDIA_ERROR_INVALID_PARAMETER;
762 }
763 return image->getHardwareBuffer(buffer);
764}