blob: 87b649ad419cc7745908907b56c664de298ae0b2 [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>
26#include <android_runtime/android_hardware_HardwareBuffer.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
40// Can only be called by free() with mLock hold
41AImage::~AImage() {
42 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 Yeh55fc8e72017-09-19 17:28:25 -070056 lockReader();
Yin-Chia Yehc3603822016-01-18 22:11:19 -080057 Mutex::Autolock _l(mLock);
58 if (mIsClosed) {
59 return;
60 }
61 sp<AImageReader> reader = mReader.promote();
Yin-Chia Yeh55fc8e72017-09-19 17:28:25 -070062 if (reader != nullptr) {
63 reader->releaseImageLocked(this, releaseFenceFd);
64 } else if (mBuffer != nullptr) {
65 LOG_ALWAYS_FATAL("%s: parent AImageReader closed without releasing image %p",
66 __FUNCTION__, this);
Yin-Chia Yehc3603822016-01-18 22:11:19 -080067 }
Yin-Chia Yeh55fc8e72017-09-19 17:28:25 -070068
Yin-Chia Yehc3603822016-01-18 22:11:19 -080069 // Should have been set to nullptr in releaseImageLocked
70 // Set to nullptr here for extra safety only
71 mBuffer = nullptr;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080072 mLockedBuffer = nullptr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -080073 mIsClosed = true;
Yin-Chia Yeh55fc8e72017-09-19 17:28:25 -070074 unlockReader();
Yin-Chia Yehc3603822016-01-18 22:11:19 -080075}
76
77void
78AImage::free() {
79 if (!isClosed()) {
80 ALOGE("Cannot free AImage before close!");
81 return;
82 }
83 Mutex::Autolock _l(mLock);
84 delete this;
85}
86
87void
88AImage::lockReader() const {
89 sp<AImageReader> reader = mReader.promote();
90 if (reader == nullptr) {
91 // Reader has been closed
92 return;
93 }
94 reader->mLock.lock();
95}
96
97void
98AImage::unlockReader() const {
99 sp<AImageReader> reader = mReader.promote();
100 if (reader == nullptr) {
101 // Reader has been closed
102 return;
103 }
104 reader->mLock.unlock();
105}
106
107media_status_t
108AImage::getWidth(int32_t* width) const {
109 if (width == nullptr) {
110 return AMEDIA_ERROR_INVALID_PARAMETER;
111 }
112 *width = -1;
113 if (isClosed()) {
114 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
115 return AMEDIA_ERROR_INVALID_OBJECT;
116 }
117 *width = mWidth;
118 return AMEDIA_OK;
119}
120
121media_status_t
122AImage::getHeight(int32_t* height) const {
123 if (height == nullptr) {
124 return AMEDIA_ERROR_INVALID_PARAMETER;
125 }
126 *height = -1;
127 if (isClosed()) {
128 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
129 return AMEDIA_ERROR_INVALID_OBJECT;
130 }
131 *height = mHeight;
132 return AMEDIA_OK;
133}
134
135media_status_t
136AImage::getFormat(int32_t* format) const {
137 if (format == nullptr) {
138 return AMEDIA_ERROR_INVALID_PARAMETER;
139 }
140 *format = -1;
141 if (isClosed()) {
142 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
143 return AMEDIA_ERROR_INVALID_OBJECT;
144 }
145 *format = mFormat;
146 return AMEDIA_OK;
147}
148
149media_status_t
150AImage::getNumPlanes(int32_t* numPlanes) const {
151 if (numPlanes == nullptr) {
152 return AMEDIA_ERROR_INVALID_PARAMETER;
153 }
154 *numPlanes = -1;
155 if (isClosed()) {
156 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
157 return AMEDIA_ERROR_INVALID_OBJECT;
158 }
159 *numPlanes = mNumPlanes;
160 return AMEDIA_OK;
161}
162
163media_status_t
164AImage::getTimestamp(int64_t* timestamp) const {
165 if (timestamp == nullptr) {
166 return AMEDIA_ERROR_INVALID_PARAMETER;
167 }
168 *timestamp = -1;
169 if (isClosed()) {
170 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
171 return AMEDIA_ERROR_INVALID_OBJECT;
172 }
173 *timestamp = mTimestamp;
174 return AMEDIA_OK;
175}
176
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800177media_status_t AImage::lockImage() {
178 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
179 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
180 return AMEDIA_ERROR_INVALID_OBJECT;
181 }
182
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700183 if ((mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800184 ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700185 __FUNCTION__, this, mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800186 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
187 }
188
189 if (mLockedBuffer != nullptr) {
190 // Return immediately if the image has already been locked.
191 return AMEDIA_OK;
192 }
193
194 auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>();
195
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700196 uint64_t grallocUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800197
198 status_t ret =
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700199 lockImageFromBuffer(mBuffer, grallocUsage, mBuffer->mFence->dup(), lockedBuffer.get());
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800200 if (ret != OK) {
201 ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret);
202 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
203 }
204
205 ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this);
206 mLockedBuffer = std::move(lockedBuffer);
207
208 return AMEDIA_OK;
209}
210
211media_status_t AImage::unlockImageIfLocked(int* fenceFd) {
212 if (fenceFd == nullptr) {
213 LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__);
214 return AMEDIA_ERROR_INVALID_PARAMETER;
215 }
216
217 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
218 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
219 return AMEDIA_ERROR_INVALID_OBJECT;
220 }
221
222 if (mLockedBuffer == nullptr) {
223 // This image hasn't been locked yet, no need to unlock.
224 *fenceFd = -1;
225 return AMEDIA_OK;
226 }
227
228 // No fence by default.
229 int releaseFenceFd = -1;
230 status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd);
231 if (res != OK) {
232 ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this);
233 *fenceFd = -1;
234 return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE;
235 }
236
237 *fenceFd = releaseFenceFd;
238 return AMEDIA_OK;
239}
240
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800241media_status_t
242AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800243 if (mLockedBuffer == nullptr) {
244 ALOGE("%s: buffer not locked.", __FUNCTION__);
245 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
246 }
247
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800248 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
249 ALOGE("Error: planeIdx %d out of bound [0,%d]",
250 planeIdx, mNumPlanes - 1);
251 return AMEDIA_ERROR_INVALID_PARAMETER;
252 }
253 if (pixelStride == nullptr) {
254 return AMEDIA_ERROR_INVALID_PARAMETER;
255 }
256 if (isClosed()) {
257 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
258 return AMEDIA_ERROR_INVALID_OBJECT;
259 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800260 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800261 switch (fmt) {
262 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800263 *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800264 return AMEDIA_OK;
265 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
266 *pixelStride = (planeIdx == 0) ? 1 : 2;
267 return AMEDIA_OK;
268 case HAL_PIXEL_FORMAT_Y8:
269 *pixelStride = 1;
270 return AMEDIA_OK;
271 case HAL_PIXEL_FORMAT_YV12:
272 *pixelStride = 1;
273 return AMEDIA_OK;
274 case HAL_PIXEL_FORMAT_Y16:
275 case HAL_PIXEL_FORMAT_RAW16:
276 case HAL_PIXEL_FORMAT_RGB_565:
277 // Single plane 16bpp data.
278 *pixelStride = 2;
279 return AMEDIA_OK;
280 case HAL_PIXEL_FORMAT_RGBA_8888:
281 case HAL_PIXEL_FORMAT_RGBX_8888:
282 *pixelStride = 4;
283 return AMEDIA_OK;
284 case HAL_PIXEL_FORMAT_RGB_888:
285 // Single plane, 24bpp.
286 *pixelStride = 3;
287 return AMEDIA_OK;
288 case HAL_PIXEL_FORMAT_BLOB:
289 case HAL_PIXEL_FORMAT_RAW10:
290 case HAL_PIXEL_FORMAT_RAW12:
291 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
292 // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
293 // those are single plane data without pixel stride defined
294 return AMEDIA_ERROR_UNSUPPORTED;
295 default:
296 ALOGE("Pixel format: 0x%x is unsupported", fmt);
297 return AMEDIA_ERROR_UNSUPPORTED;
298 }
299}
300
301media_status_t
302AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800303 if (mLockedBuffer == nullptr) {
304 ALOGE("%s: buffer not locked.", __FUNCTION__);
305 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
306 }
307
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800308 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
309 ALOGE("Error: planeIdx %d out of bound [0,%d]",
310 planeIdx, mNumPlanes - 1);
311 return AMEDIA_ERROR_INVALID_PARAMETER;
312 }
313 if (rowStride == nullptr) {
314 return AMEDIA_ERROR_INVALID_PARAMETER;
315 }
316 if (isClosed()) {
317 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
318 return AMEDIA_ERROR_INVALID_OBJECT;
319 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800320 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800321 switch (fmt) {
322 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800323 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
324 : mLockedBuffer->chromaStride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800325 return AMEDIA_OK;
326 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800327 *rowStride = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800328 return AMEDIA_OK;
329 case HAL_PIXEL_FORMAT_YV12:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800330 if (mLockedBuffer->stride % 16) {
331 ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800332 return AMEDIA_ERROR_UNKNOWN;
333 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800334 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
335 : ALIGN(mLockedBuffer->stride / 2, 16);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800336 return AMEDIA_OK;
337 case HAL_PIXEL_FORMAT_RAW10:
338 case HAL_PIXEL_FORMAT_RAW12:
339 // 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 -0800340 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800341 return AMEDIA_OK;
342 case HAL_PIXEL_FORMAT_Y8:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800343 if (mLockedBuffer->stride % 16) {
344 ALOGE("Stride %d is not 16 pixel aligned!",
345 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800346 return AMEDIA_ERROR_UNKNOWN;
347 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800348 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800349 return AMEDIA_OK;
350 case HAL_PIXEL_FORMAT_Y16:
351 case HAL_PIXEL_FORMAT_RAW16:
352 // In native side, strides are specified in pixels, not in bytes.
353 // Single plane 16bpp bayer data. even width/height,
354 // row stride multiple of 16 pixels (32 bytes)
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800355 if (mLockedBuffer->stride % 16) {
356 ALOGE("Stride %d is not 16 pixel aligned!",
357 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800358 return AMEDIA_ERROR_UNKNOWN;
359 }
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_RGB_565:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800363 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800364 return AMEDIA_OK;
365 case HAL_PIXEL_FORMAT_RGBA_8888:
366 case HAL_PIXEL_FORMAT_RGBX_8888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800367 *rowStride = mLockedBuffer->stride * 4;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800368 return AMEDIA_OK;
369 case HAL_PIXEL_FORMAT_RGB_888:
370 // Single plane, 24bpp.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800371 *rowStride = mLockedBuffer->stride * 3;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800372 return AMEDIA_OK;
373 case HAL_PIXEL_FORMAT_BLOB:
374 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
375 // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
376 // no row stride defined
377 return AMEDIA_ERROR_UNSUPPORTED;
378 default:
379 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
380 return AMEDIA_ERROR_UNSUPPORTED;
381 }
382}
383
384uint32_t
385AImage::getJpegSize() const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800386 if (mLockedBuffer == nullptr) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800387 LOG_ALWAYS_FATAL("Error: buffer is null");
388 }
389
390 uint32_t size = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800391 uint32_t width = mLockedBuffer->width;
392 uint8_t* jpegBuffer = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800393
394 // First check for JPEG transport header at the end of the buffer
395 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
396 struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
397 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
398 size = blob->jpeg_size;
399 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
400 }
401
402 // failed to find size, default to whole buffer
403 if (size == 0) {
404 /*
405 * This is a problem because not including the JPEG header
406 * means that in certain rare situations a regular JPEG blob
407 * will be misidentified as having a header, in which case
408 * we will get a garbage size value.
409 */
410 ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
411 __FUNCTION__, width);
412 size = width;
413 }
414
415 return size;
416}
417
418media_status_t
419AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800420 if (mLockedBuffer == nullptr) {
421 ALOGE("%s: buffer not locked.", __FUNCTION__);
422 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
423 }
424
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800425 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
426 ALOGE("Error: planeIdx %d out of bound [0,%d]",
427 planeIdx, mNumPlanes - 1);
428 return AMEDIA_ERROR_INVALID_PARAMETER;
429 }
430 if (data == nullptr || dataLength == nullptr) {
431 return AMEDIA_ERROR_INVALID_PARAMETER;
432 }
433 if (isClosed()) {
434 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
435 return AMEDIA_ERROR_INVALID_OBJECT;
436 }
437
438 uint32_t dataSize, ySize, cSize, cStride;
439 uint8_t* cb = nullptr;
440 uint8_t* cr = nullptr;
441 uint8_t* pData = nullptr;
442 int bytesPerPixel = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800443 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800444
445 switch (fmt) {
446 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800447 pData = (planeIdx == 0) ? mLockedBuffer->data
448 : (planeIdx == 1) ? mLockedBuffer->dataCb
449 : mLockedBuffer->dataCr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800450 // only map until last pixel
451 if (planeIdx == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800452 dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) +
453 mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800454 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800455 dataSize =
456 mLockedBuffer->chromaStride *
457 (mLockedBuffer->height / 2 - 1) +
458 mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) +
459 1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800460 }
461 break;
462 // NV21
463 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800464 cr = mLockedBuffer->data +
465 (mLockedBuffer->stride * mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800466 cb = cr + 1;
467 // only map until last pixel
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800468 ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) +
469 mLockedBuffer->width;
470 cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) +
471 mLockedBuffer->width - 1;
472 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_YV12:
477 // Y and C stride need to be 16 pixel aligned.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800478 if (mLockedBuffer->stride % 16) {
479 ALOGE("Stride %d is not 16 pixel aligned!",
480 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800481 return AMEDIA_ERROR_UNKNOWN;
482 }
483
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800484 ySize = mLockedBuffer->stride * mLockedBuffer->height;
485 cStride = ALIGN(mLockedBuffer->stride / 2, 16);
486 cr = mLockedBuffer->data + ySize;
487 cSize = cStride * mLockedBuffer->height / 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800488 cb = cr + cSize;
489
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800490 pData = (planeIdx == 0) ? mLockedBuffer->data
491 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800492 dataSize = (planeIdx == 0) ? ySize : cSize;
493 break;
494 case HAL_PIXEL_FORMAT_Y8:
495 // Single plane, 8bpp.
496
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800497 pData = mLockedBuffer->data;
498 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800499 break;
500 case HAL_PIXEL_FORMAT_Y16:
501 bytesPerPixel = 2;
502
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_BLOB:
508 // Used for JPEG data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800509 if (mLockedBuffer->height != 1) {
510 ALOGE("Jpeg 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 }
514
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800515 pData = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800516 dataSize = getJpegSize();
517 break;
518 case HAL_PIXEL_FORMAT_RAW16:
519 // Single plane 16bpp bayer data.
520 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800521 pData = mLockedBuffer->data;
522 dataSize =
523 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800524 break;
525 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
526 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800527 if (mLockedBuffer->height != 1) {
528 ALOGE("RAW_OPAQUE should have height value one but got %d",
529 mLockedBuffer->height);
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->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800534 break;
535 case HAL_PIXEL_FORMAT_RAW10:
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 * 10 / 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 * 10 / 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_RAW12:
554 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800555 if (mLockedBuffer->width % 4) {
556 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800557 return AMEDIA_ERROR_UNKNOWN;
558 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800559 if (mLockedBuffer->height % 2) {
560 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800561 return AMEDIA_ERROR_UNKNOWN;
562 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800563 if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800564 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800565 mLockedBuffer->stride, mLockedBuffer->width * 12 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800566 return AMEDIA_ERROR_UNKNOWN;
567 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800568 pData = mLockedBuffer->data;
569 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800570 break;
571 case HAL_PIXEL_FORMAT_RGBA_8888:
572 case HAL_PIXEL_FORMAT_RGBX_8888:
573 // Single plane, 32bpp.
574 bytesPerPixel = 4;
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_RGB_565:
580 // Single plane, 16bpp.
581 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800582 pData = mLockedBuffer->data;
583 dataSize =
584 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800585 break;
586 case HAL_PIXEL_FORMAT_RGB_888:
587 // Single plane, 24bpp.
588 bytesPerPixel = 3;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800589 pData = mLockedBuffer->data;
590 dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800591 break;
592 default:
593 ALOGE("Pixel format: 0x%x is unsupported", fmt);
594 return AMEDIA_ERROR_UNSUPPORTED;
595 }
596
597 *data = pData;
598 *dataLength = dataSize;
599 return AMEDIA_OK;
600}
601
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800602media_status_t
603AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const {
604 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
605 ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this);
606 return AMEDIA_ERROR_INVALID_OBJECT;
607 }
608
609 // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast.
610 *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get());
611 return AMEDIA_OK;
612}
613
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800614EXPORT
615void AImage_delete(AImage* image) {
616 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800617 AImage_deleteAsync(image, -1);
618 return;
619}
620
621EXPORT
622void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
623 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800624 if (image != nullptr) {
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800625 image->close(releaseFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800626 if (!image->isClosed()) {
627 LOG_ALWAYS_FATAL("Image close failed!");
628 }
629 image->free();
630 }
631 return;
632}
633
634EXPORT
635media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
636 ALOGV("%s", __FUNCTION__);
637 if (image == nullptr || width == nullptr) {
638 ALOGE("%s: bad argument. image %p width %p",
639 __FUNCTION__, image, width);
640 return AMEDIA_ERROR_INVALID_PARAMETER;
641 }
642 return image->getWidth(width);
643}
644
645EXPORT
646media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
647 ALOGV("%s", __FUNCTION__);
648 if (image == nullptr || height == nullptr) {
649 ALOGE("%s: bad argument. image %p height %p",
650 __FUNCTION__, image, height);
651 return AMEDIA_ERROR_INVALID_PARAMETER;
652 }
653 return image->getHeight(height);
654}
655
656EXPORT
657media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
658 ALOGV("%s", __FUNCTION__);
659 if (image == nullptr || format == nullptr) {
660 ALOGE("%s: bad argument. image %p format %p",
661 __FUNCTION__, image, format);
662 return AMEDIA_ERROR_INVALID_PARAMETER;
663 }
664 return image->getFormat(format);
665}
666
667EXPORT
668media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
669 ALOGV("%s", __FUNCTION__);
670 if (image == nullptr || rect == nullptr) {
671 ALOGE("%s: bad argument. image %p rect %p",
672 __FUNCTION__, image, rect);
673 return AMEDIA_ERROR_INVALID_PARAMETER;
674 }
675 // For now AImage only supports camera outputs where cropRect is always full window
676 int32_t width = -1;
677 media_status_t ret = image->getWidth(&width);
678 if (ret != AMEDIA_OK) {
679 return ret;
680 }
681 int32_t height = -1;
682 ret = image->getHeight(&height);
683 if (ret != AMEDIA_OK) {
684 return ret;
685 }
686 rect->left = 0;
687 rect->top = 0;
688 rect->right = width;
689 rect->bottom = height;
690 return AMEDIA_OK;
691}
692
693EXPORT
694media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
695 ALOGV("%s", __FUNCTION__);
696 if (image == nullptr || timestampNs == nullptr) {
697 ALOGE("%s: bad argument. image %p timestampNs %p",
698 __FUNCTION__, image, timestampNs);
699 return AMEDIA_ERROR_INVALID_PARAMETER;
700 }
701 return image->getTimestamp(timestampNs);
702}
703
704EXPORT
705media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
706 ALOGV("%s", __FUNCTION__);
707 if (image == nullptr || numPlanes == nullptr) {
708 ALOGE("%s: bad argument. image %p numPlanes %p",
709 __FUNCTION__, image, numPlanes);
710 return AMEDIA_ERROR_INVALID_PARAMETER;
711 }
712 return image->getNumPlanes(numPlanes);
713}
714
715EXPORT
716media_status_t AImage_getPlanePixelStride(
717 const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
718 ALOGV("%s", __FUNCTION__);
719 if (image == nullptr || pixelStride == nullptr) {
720 ALOGE("%s: bad argument. image %p pixelStride %p",
721 __FUNCTION__, image, pixelStride);
722 return AMEDIA_ERROR_INVALID_PARAMETER;
723 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800724 media_status_t ret = const_cast<AImage*>(image)->lockImage();
725 if (ret != AMEDIA_OK) {
726 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
727 __FUNCTION__, image, ret);
728 return ret;
729 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800730 return image->getPlanePixelStride(planeIdx, pixelStride);
731}
732
733EXPORT
734media_status_t AImage_getPlaneRowStride(
735 const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
736 ALOGV("%s", __FUNCTION__);
737 if (image == nullptr || rowStride == nullptr) {
738 ALOGE("%s: bad argument. image %p rowStride %p",
739 __FUNCTION__, image, rowStride);
740 return AMEDIA_ERROR_INVALID_PARAMETER;
741 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800742 media_status_t ret = const_cast<AImage*>(image)->lockImage();
743 if (ret != AMEDIA_OK) {
744 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
745 __FUNCTION__, image, ret);
746 return ret;
747 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800748 return image->getPlaneRowStride(planeIdx, rowStride);
749}
750
751EXPORT
752media_status_t AImage_getPlaneData(
753 const AImage* image, int planeIdx,
754 /*out*/uint8_t** data, /*out*/int* dataLength) {
755 ALOGV("%s", __FUNCTION__);
756 if (image == nullptr || data == nullptr || dataLength == nullptr) {
757 ALOGE("%s: bad argument. image %p data %p dataLength %p",
758 __FUNCTION__, image, data, dataLength);
759 return AMEDIA_ERROR_INVALID_PARAMETER;
760 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800761 media_status_t ret = const_cast<AImage*>(image)->lockImage();
762 if (ret != AMEDIA_OK) {
763 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
764 __FUNCTION__, image, ret);
765 return ret;
766 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800767 return image->getPlaneData(planeIdx, data, dataLength);
768}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800769
770EXPORT
771media_status_t AImage_getHardwareBuffer(
772 const AImage* image, /*out*/AHardwareBuffer** buffer) {
773 ALOGV("%s", __FUNCTION__);
774
775 if (image == nullptr || buffer == nullptr) {
776 ALOGE("%s: bad argument. image %p buffer %p", __FUNCTION__, image, buffer);
777 return AMEDIA_ERROR_INVALID_PARAMETER;
778 }
779 return image->getHardwareBuffer(buffer);
780}