blob: 1883f6356d24de6b5dd6a134b5b9e894e948a085 [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>
28#include "hardware/camera3.h"
29
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) {
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 }
60 sp<AImageReader> reader = mReader.promote();
Yin-Chia Yeh55fc8e72017-09-19 17:28:25 -070061 if (reader != nullptr) {
62 reader->releaseImageLocked(this, releaseFenceFd);
63 } else if (mBuffer != nullptr) {
64 LOG_ALWAYS_FATAL("%s: parent AImageReader closed without releasing image %p",
65 __FUNCTION__, this);
Yin-Chia Yehc3603822016-01-18 22:11:19 -080066 }
Yin-Chia Yeh55fc8e72017-09-19 17:28:25 -070067
Yin-Chia Yehc3603822016-01-18 22:11:19 -080068 // Should have been set to nullptr in releaseImageLocked
69 // Set to nullptr here for extra safety only
70 mBuffer = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080071 mLockedBuffer = nullptr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080072 mIsClosed = true;
73}
74
75void
76AImage::free() {
77 if (!isClosed()) {
78 ALOGE("Cannot free AImage before close!");
79 return;
80 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -080081 delete this;
82}
83
84void
85AImage::lockReader() const {
86 sp<AImageReader> reader = mReader.promote();
87 if (reader == nullptr) {
88 // Reader has been closed
89 return;
90 }
91 reader->mLock.lock();
92}
93
94void
95AImage::unlockReader() const {
96 sp<AImageReader> reader = mReader.promote();
97 if (reader == nullptr) {
98 // Reader has been closed
99 return;
100 }
101 reader->mLock.unlock();
102}
103
104media_status_t
105AImage::getWidth(int32_t* width) const {
106 if (width == nullptr) {
107 return AMEDIA_ERROR_INVALID_PARAMETER;
108 }
109 *width = -1;
110 if (isClosed()) {
111 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
112 return AMEDIA_ERROR_INVALID_OBJECT;
113 }
114 *width = mWidth;
115 return AMEDIA_OK;
116}
117
118media_status_t
119AImage::getHeight(int32_t* height) const {
120 if (height == nullptr) {
121 return AMEDIA_ERROR_INVALID_PARAMETER;
122 }
123 *height = -1;
124 if (isClosed()) {
125 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
126 return AMEDIA_ERROR_INVALID_OBJECT;
127 }
128 *height = mHeight;
129 return AMEDIA_OK;
130}
131
132media_status_t
133AImage::getFormat(int32_t* format) const {
134 if (format == nullptr) {
135 return AMEDIA_ERROR_INVALID_PARAMETER;
136 }
137 *format = -1;
138 if (isClosed()) {
139 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
140 return AMEDIA_ERROR_INVALID_OBJECT;
141 }
142 *format = mFormat;
143 return AMEDIA_OK;
144}
145
146media_status_t
147AImage::getNumPlanes(int32_t* numPlanes) const {
148 if (numPlanes == nullptr) {
149 return AMEDIA_ERROR_INVALID_PARAMETER;
150 }
151 *numPlanes = -1;
152 if (isClosed()) {
153 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
154 return AMEDIA_ERROR_INVALID_OBJECT;
155 }
156 *numPlanes = mNumPlanes;
157 return AMEDIA_OK;
158}
159
160media_status_t
161AImage::getTimestamp(int64_t* timestamp) const {
162 if (timestamp == nullptr) {
163 return AMEDIA_ERROR_INVALID_PARAMETER;
164 }
165 *timestamp = -1;
166 if (isClosed()) {
167 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
168 return AMEDIA_ERROR_INVALID_OBJECT;
169 }
170 *timestamp = mTimestamp;
171 return AMEDIA_OK;
172}
173
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800174media_status_t AImage::lockImage() {
175 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
176 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
177 return AMEDIA_ERROR_INVALID_OBJECT;
178 }
179
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700180 if ((mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800181 ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700182 __FUNCTION__, this, mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800183 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
184 }
185
186 if (mLockedBuffer != nullptr) {
187 // Return immediately if the image has already been locked.
188 return AMEDIA_OK;
189 }
190
191 auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>();
192
Jooyung Hanfe304592019-02-21 15:12:59 +0900193 uint64_t grallocUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800194
195 status_t ret =
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700196 lockImageFromBuffer(mBuffer, grallocUsage, mBuffer->mFence->dup(), lockedBuffer.get());
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800197 if (ret != OK) {
198 ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret);
199 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
200 }
201
202 ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this);
203 mLockedBuffer = std::move(lockedBuffer);
204
205 return AMEDIA_OK;
206}
207
208media_status_t AImage::unlockImageIfLocked(int* fenceFd) {
209 if (fenceFd == nullptr) {
210 LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__);
211 return AMEDIA_ERROR_INVALID_PARAMETER;
212 }
213
214 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
215 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
216 return AMEDIA_ERROR_INVALID_OBJECT;
217 }
218
219 if (mLockedBuffer == nullptr) {
220 // This image hasn't been locked yet, no need to unlock.
221 *fenceFd = -1;
222 return AMEDIA_OK;
223 }
224
225 // No fence by default.
226 int releaseFenceFd = -1;
227 status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd);
228 if (res != OK) {
229 ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this);
230 *fenceFd = -1;
231 return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE;
232 }
233
234 *fenceFd = releaseFenceFd;
235 return AMEDIA_OK;
236}
237
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800238media_status_t
239AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800240 if (mLockedBuffer == nullptr) {
241 ALOGE("%s: buffer not locked.", __FUNCTION__);
242 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
243 }
244
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800245 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
246 ALOGE("Error: planeIdx %d out of bound [0,%d]",
247 planeIdx, mNumPlanes - 1);
248 return AMEDIA_ERROR_INVALID_PARAMETER;
249 }
250 if (pixelStride == nullptr) {
251 return AMEDIA_ERROR_INVALID_PARAMETER;
252 }
253 if (isClosed()) {
254 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
255 return AMEDIA_ERROR_INVALID_OBJECT;
256 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800257 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800258 switch (fmt) {
259 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800260 *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800261 return AMEDIA_OK;
262 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
263 *pixelStride = (planeIdx == 0) ? 1 : 2;
264 return AMEDIA_OK;
265 case HAL_PIXEL_FORMAT_Y8:
266 *pixelStride = 1;
267 return AMEDIA_OK;
268 case HAL_PIXEL_FORMAT_YV12:
269 *pixelStride = 1;
270 return AMEDIA_OK;
271 case HAL_PIXEL_FORMAT_Y16:
272 case HAL_PIXEL_FORMAT_RAW16:
273 case HAL_PIXEL_FORMAT_RGB_565:
274 // Single plane 16bpp data.
275 *pixelStride = 2;
276 return AMEDIA_OK;
277 case HAL_PIXEL_FORMAT_RGBA_8888:
278 case HAL_PIXEL_FORMAT_RGBX_8888:
279 *pixelStride = 4;
280 return AMEDIA_OK;
281 case HAL_PIXEL_FORMAT_RGB_888:
282 // Single plane, 24bpp.
283 *pixelStride = 3;
284 return AMEDIA_OK;
285 case HAL_PIXEL_FORMAT_BLOB:
286 case HAL_PIXEL_FORMAT_RAW10:
287 case HAL_PIXEL_FORMAT_RAW12:
288 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
289 // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
290 // those are single plane data without pixel stride defined
291 return AMEDIA_ERROR_UNSUPPORTED;
292 default:
293 ALOGE("Pixel format: 0x%x is unsupported", fmt);
294 return AMEDIA_ERROR_UNSUPPORTED;
295 }
296}
297
298media_status_t
299AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800300 if (mLockedBuffer == nullptr) {
301 ALOGE("%s: buffer not locked.", __FUNCTION__);
302 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
303 }
304
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800305 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
306 ALOGE("Error: planeIdx %d out of bound [0,%d]",
307 planeIdx, mNumPlanes - 1);
308 return AMEDIA_ERROR_INVALID_PARAMETER;
309 }
310 if (rowStride == nullptr) {
311 return AMEDIA_ERROR_INVALID_PARAMETER;
312 }
313 if (isClosed()) {
314 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
315 return AMEDIA_ERROR_INVALID_OBJECT;
316 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800317 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800318 switch (fmt) {
319 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800320 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
321 : mLockedBuffer->chromaStride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800322 return AMEDIA_OK;
323 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800324 *rowStride = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800325 return AMEDIA_OK;
326 case HAL_PIXEL_FORMAT_YV12:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800327 if (mLockedBuffer->stride % 16) {
328 ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800329 return AMEDIA_ERROR_UNKNOWN;
330 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800331 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
332 : ALIGN(mLockedBuffer->stride / 2, 16);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800333 return AMEDIA_OK;
334 case HAL_PIXEL_FORMAT_RAW10:
335 case HAL_PIXEL_FORMAT_RAW12:
336 // 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 -0800337 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800338 return AMEDIA_OK;
339 case HAL_PIXEL_FORMAT_Y8:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800340 if (mLockedBuffer->stride % 16) {
341 ALOGE("Stride %d is not 16 pixel aligned!",
342 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800343 return AMEDIA_ERROR_UNKNOWN;
344 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800345 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800346 return AMEDIA_OK;
347 case HAL_PIXEL_FORMAT_Y16:
348 case HAL_PIXEL_FORMAT_RAW16:
349 // In native side, strides are specified in pixels, not in bytes.
350 // Single plane 16bpp bayer data. even width/height,
351 // row stride multiple of 16 pixels (32 bytes)
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800352 if (mLockedBuffer->stride % 16) {
353 ALOGE("Stride %d is not 16 pixel aligned!",
354 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800355 return AMEDIA_ERROR_UNKNOWN;
356 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800357 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800358 return AMEDIA_OK;
359 case HAL_PIXEL_FORMAT_RGB_565:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800360 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800361 return AMEDIA_OK;
362 case HAL_PIXEL_FORMAT_RGBA_8888:
363 case HAL_PIXEL_FORMAT_RGBX_8888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800364 *rowStride = mLockedBuffer->stride * 4;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800365 return AMEDIA_OK;
366 case HAL_PIXEL_FORMAT_RGB_888:
367 // Single plane, 24bpp.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800368 *rowStride = mLockedBuffer->stride * 3;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800369 return AMEDIA_OK;
370 case HAL_PIXEL_FORMAT_BLOB:
371 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
372 // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
373 // no row stride defined
374 return AMEDIA_ERROR_UNSUPPORTED;
375 default:
376 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
377 return AMEDIA_ERROR_UNSUPPORTED;
378 }
379}
380
381uint32_t
382AImage::getJpegSize() const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800383 if (mLockedBuffer == nullptr) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800384 LOG_ALWAYS_FATAL("Error: buffer is null");
385 }
386
387 uint32_t size = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800388 uint32_t width = mLockedBuffer->width;
389 uint8_t* jpegBuffer = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800390
391 // First check for JPEG transport header at the end of the buffer
392 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
393 struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
394 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
395 size = blob->jpeg_size;
396 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
397 }
398
399 // failed to find size, default to whole buffer
400 if (size == 0) {
401 /*
402 * This is a problem because not including the JPEG header
403 * means that in certain rare situations a regular JPEG blob
404 * will be misidentified as having a header, in which case
405 * we will get a garbage size value.
406 */
407 ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
408 __FUNCTION__, width);
409 size = width;
410 }
411
412 return size;
413}
414
415media_status_t
416AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800417 if (mLockedBuffer == nullptr) {
418 ALOGE("%s: buffer not locked.", __FUNCTION__);
419 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
420 }
421
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800422 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
423 ALOGE("Error: planeIdx %d out of bound [0,%d]",
424 planeIdx, mNumPlanes - 1);
425 return AMEDIA_ERROR_INVALID_PARAMETER;
426 }
427 if (data == nullptr || dataLength == nullptr) {
428 return AMEDIA_ERROR_INVALID_PARAMETER;
429 }
430 if (isClosed()) {
431 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
432 return AMEDIA_ERROR_INVALID_OBJECT;
433 }
434
435 uint32_t dataSize, ySize, cSize, cStride;
436 uint8_t* cb = nullptr;
437 uint8_t* cr = nullptr;
438 uint8_t* pData = nullptr;
439 int bytesPerPixel = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800440 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800441
442 switch (fmt) {
443 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800444 pData = (planeIdx == 0) ? mLockedBuffer->data
445 : (planeIdx == 1) ? mLockedBuffer->dataCb
446 : mLockedBuffer->dataCr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800447 // only map until last pixel
448 if (planeIdx == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800449 dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) +
450 mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800451 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800452 dataSize =
453 mLockedBuffer->chromaStride *
454 (mLockedBuffer->height / 2 - 1) +
455 mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) +
456 1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800457 }
458 break;
459 // NV21
460 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800461 cr = mLockedBuffer->data +
462 (mLockedBuffer->stride * mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800463 cb = cr + 1;
464 // only map until last pixel
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800465 ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) +
466 mLockedBuffer->width;
467 cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) +
468 mLockedBuffer->width - 1;
469 pData = (planeIdx == 0) ? mLockedBuffer->data
470 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800471 dataSize = (planeIdx == 0) ? ySize : cSize;
472 break;
473 case HAL_PIXEL_FORMAT_YV12:
474 // Y and C stride need to be 16 pixel aligned.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800475 if (mLockedBuffer->stride % 16) {
476 ALOGE("Stride %d is not 16 pixel aligned!",
477 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800478 return AMEDIA_ERROR_UNKNOWN;
479 }
480
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800481 ySize = mLockedBuffer->stride * mLockedBuffer->height;
482 cStride = ALIGN(mLockedBuffer->stride / 2, 16);
483 cr = mLockedBuffer->data + ySize;
484 cSize = cStride * mLockedBuffer->height / 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800485 cb = cr + cSize;
486
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800487 pData = (planeIdx == 0) ? mLockedBuffer->data
488 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800489 dataSize = (planeIdx == 0) ? ySize : cSize;
490 break;
491 case HAL_PIXEL_FORMAT_Y8:
492 // Single plane, 8bpp.
493
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800494 pData = mLockedBuffer->data;
495 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800496 break;
497 case HAL_PIXEL_FORMAT_Y16:
498 bytesPerPixel = 2;
499
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800500 pData = mLockedBuffer->data;
501 dataSize =
502 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800503 break;
504 case HAL_PIXEL_FORMAT_BLOB:
505 // Used for JPEG data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800506 if (mLockedBuffer->height != 1) {
507 ALOGE("Jpeg should have height value one but got %d",
508 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800509 return AMEDIA_ERROR_UNKNOWN;
510 }
511
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800512 pData = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800513 dataSize = getJpegSize();
514 break;
515 case HAL_PIXEL_FORMAT_RAW16:
516 // Single plane 16bpp bayer data.
517 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800518 pData = mLockedBuffer->data;
519 dataSize =
520 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800521 break;
522 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
523 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800524 if (mLockedBuffer->height != 1) {
525 ALOGE("RAW_OPAQUE should have height value one but got %d",
526 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800527 return AMEDIA_ERROR_UNKNOWN;
528 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800529 pData = mLockedBuffer->data;
530 dataSize = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800531 break;
532 case HAL_PIXEL_FORMAT_RAW10:
533 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800534 if (mLockedBuffer->width % 4) {
535 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800536 return AMEDIA_ERROR_UNKNOWN;
537 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800538 if (mLockedBuffer->height % 2) {
539 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800540 return AMEDIA_ERROR_UNKNOWN;
541 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800542 if (mLockedBuffer->stride < (mLockedBuffer->width * 10 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800543 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800544 mLockedBuffer->stride, mLockedBuffer->width * 10 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800545 return AMEDIA_ERROR_UNKNOWN;
546 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800547 pData = mLockedBuffer->data;
548 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800549 break;
550 case HAL_PIXEL_FORMAT_RAW12:
551 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800552 if (mLockedBuffer->width % 4) {
553 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800554 return AMEDIA_ERROR_UNKNOWN;
555 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800556 if (mLockedBuffer->height % 2) {
557 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800558 return AMEDIA_ERROR_UNKNOWN;
559 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800560 if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800561 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800562 mLockedBuffer->stride, mLockedBuffer->width * 12 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800563 return AMEDIA_ERROR_UNKNOWN;
564 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800565 pData = mLockedBuffer->data;
566 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800567 break;
568 case HAL_PIXEL_FORMAT_RGBA_8888:
569 case HAL_PIXEL_FORMAT_RGBX_8888:
570 // Single plane, 32bpp.
571 bytesPerPixel = 4;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800572 pData = mLockedBuffer->data;
573 dataSize =
574 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800575 break;
576 case HAL_PIXEL_FORMAT_RGB_565:
577 // Single plane, 16bpp.
578 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800579 pData = mLockedBuffer->data;
580 dataSize =
581 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800582 break;
583 case HAL_PIXEL_FORMAT_RGB_888:
584 // Single plane, 24bpp.
585 bytesPerPixel = 3;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800586 pData = mLockedBuffer->data;
587 dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800588 break;
589 default:
590 ALOGE("Pixel format: 0x%x is unsupported", fmt);
591 return AMEDIA_ERROR_UNSUPPORTED;
592 }
593
594 *data = pData;
595 *dataLength = dataSize;
596 return AMEDIA_OK;
597}
598
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800599media_status_t
600AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const {
601 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
602 ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this);
603 return AMEDIA_ERROR_INVALID_OBJECT;
604 }
605
606 // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast.
607 *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get());
608 return AMEDIA_OK;
609}
610
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800611EXPORT
612void AImage_delete(AImage* image) {
613 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800614 AImage_deleteAsync(image, -1);
615 return;
616}
617
618EXPORT
619void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
620 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800621 if (image != nullptr) {
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800622 image->lockReader();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800623 image->close(releaseFenceFd);
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800624 image->unlockReader();
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800625 if (!image->isClosed()) {
626 LOG_ALWAYS_FATAL("Image close failed!");
627 }
628 image->free();
629 }
630 return;
631}
632
633EXPORT
634media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
635 ALOGV("%s", __FUNCTION__);
636 if (image == nullptr || width == nullptr) {
637 ALOGE("%s: bad argument. image %p width %p",
638 __FUNCTION__, image, width);
639 return AMEDIA_ERROR_INVALID_PARAMETER;
640 }
641 return image->getWidth(width);
642}
643
644EXPORT
645media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
646 ALOGV("%s", __FUNCTION__);
647 if (image == nullptr || height == nullptr) {
648 ALOGE("%s: bad argument. image %p height %p",
649 __FUNCTION__, image, height);
650 return AMEDIA_ERROR_INVALID_PARAMETER;
651 }
652 return image->getHeight(height);
653}
654
655EXPORT
656media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
657 ALOGV("%s", __FUNCTION__);
658 if (image == nullptr || format == nullptr) {
659 ALOGE("%s: bad argument. image %p format %p",
660 __FUNCTION__, image, format);
661 return AMEDIA_ERROR_INVALID_PARAMETER;
662 }
663 return image->getFormat(format);
664}
665
666EXPORT
667media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
668 ALOGV("%s", __FUNCTION__);
669 if (image == nullptr || rect == nullptr) {
670 ALOGE("%s: bad argument. image %p rect %p",
671 __FUNCTION__, image, rect);
672 return AMEDIA_ERROR_INVALID_PARAMETER;
673 }
674 // For now AImage only supports camera outputs where cropRect is always full window
675 int32_t width = -1;
676 media_status_t ret = image->getWidth(&width);
677 if (ret != AMEDIA_OK) {
678 return ret;
679 }
680 int32_t height = -1;
681 ret = image->getHeight(&height);
682 if (ret != AMEDIA_OK) {
683 return ret;
684 }
685 rect->left = 0;
686 rect->top = 0;
687 rect->right = width;
688 rect->bottom = height;
689 return AMEDIA_OK;
690}
691
692EXPORT
693media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
694 ALOGV("%s", __FUNCTION__);
695 if (image == nullptr || timestampNs == nullptr) {
696 ALOGE("%s: bad argument. image %p timestampNs %p",
697 __FUNCTION__, image, timestampNs);
698 return AMEDIA_ERROR_INVALID_PARAMETER;
699 }
700 return image->getTimestamp(timestampNs);
701}
702
703EXPORT
704media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
705 ALOGV("%s", __FUNCTION__);
706 if (image == nullptr || numPlanes == nullptr) {
707 ALOGE("%s: bad argument. image %p numPlanes %p",
708 __FUNCTION__, image, numPlanes);
709 return AMEDIA_ERROR_INVALID_PARAMETER;
710 }
711 return image->getNumPlanes(numPlanes);
712}
713
714EXPORT
715media_status_t AImage_getPlanePixelStride(
716 const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
717 ALOGV("%s", __FUNCTION__);
718 if (image == nullptr || pixelStride == nullptr) {
719 ALOGE("%s: bad argument. image %p pixelStride %p",
720 __FUNCTION__, image, pixelStride);
721 return AMEDIA_ERROR_INVALID_PARAMETER;
722 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800723 media_status_t ret = const_cast<AImage*>(image)->lockImage();
724 if (ret != AMEDIA_OK) {
725 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
726 __FUNCTION__, image, ret);
727 return ret;
728 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800729 return image->getPlanePixelStride(planeIdx, pixelStride);
730}
731
732EXPORT
733media_status_t AImage_getPlaneRowStride(
734 const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
735 ALOGV("%s", __FUNCTION__);
736 if (image == nullptr || rowStride == nullptr) {
737 ALOGE("%s: bad argument. image %p rowStride %p",
738 __FUNCTION__, image, rowStride);
739 return AMEDIA_ERROR_INVALID_PARAMETER;
740 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800741 media_status_t ret = const_cast<AImage*>(image)->lockImage();
742 if (ret != AMEDIA_OK) {
743 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
744 __FUNCTION__, image, ret);
745 return ret;
746 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800747 return image->getPlaneRowStride(planeIdx, rowStride);
748}
749
750EXPORT
751media_status_t AImage_getPlaneData(
752 const AImage* image, int planeIdx,
753 /*out*/uint8_t** data, /*out*/int* dataLength) {
754 ALOGV("%s", __FUNCTION__);
755 if (image == nullptr || data == nullptr || dataLength == nullptr) {
756 ALOGE("%s: bad argument. image %p data %p dataLength %p",
757 __FUNCTION__, image, data, dataLength);
758 return AMEDIA_ERROR_INVALID_PARAMETER;
759 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800760 media_status_t ret = const_cast<AImage*>(image)->lockImage();
761 if (ret != AMEDIA_OK) {
762 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
763 __FUNCTION__, image, ret);
764 return ret;
765 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800766 return image->getPlaneData(planeIdx, data, dataLength);
767}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800768
769EXPORT
770media_status_t AImage_getHardwareBuffer(
771 const AImage* image, /*out*/AHardwareBuffer** buffer) {
772 ALOGV("%s", __FUNCTION__);
773
774 if (image == nullptr || buffer == nullptr) {
775 ALOGE("%s: bad argument. image %p buffer %p", __FUNCTION__, image, buffer);
776 return AMEDIA_ERROR_INVALID_PARAMETER;
777 }
778 return image->getHardwareBuffer(buffer);
779}