blob: c4ff53768751883eb3bf13f04dd743a8fb83475c [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 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 }
81 Mutex::Autolock _l(mLock);
82 delete this;
83}
84
85void
86AImage::lockReader() const {
87 sp<AImageReader> reader = mReader.promote();
88 if (reader == nullptr) {
89 // Reader has been closed
90 return;
91 }
92 reader->mLock.lock();
93}
94
95void
96AImage::unlockReader() const {
97 sp<AImageReader> reader = mReader.promote();
98 if (reader == nullptr) {
99 // Reader has been closed
100 return;
101 }
102 reader->mLock.unlock();
103}
104
105media_status_t
106AImage::getWidth(int32_t* width) const {
107 if (width == nullptr) {
108 return AMEDIA_ERROR_INVALID_PARAMETER;
109 }
110 *width = -1;
111 if (isClosed()) {
112 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
113 return AMEDIA_ERROR_INVALID_OBJECT;
114 }
115 *width = mWidth;
116 return AMEDIA_OK;
117}
118
119media_status_t
120AImage::getHeight(int32_t* height) const {
121 if (height == nullptr) {
122 return AMEDIA_ERROR_INVALID_PARAMETER;
123 }
124 *height = -1;
125 if (isClosed()) {
126 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
127 return AMEDIA_ERROR_INVALID_OBJECT;
128 }
129 *height = mHeight;
130 return AMEDIA_OK;
131}
132
133media_status_t
134AImage::getFormat(int32_t* format) const {
135 if (format == nullptr) {
136 return AMEDIA_ERROR_INVALID_PARAMETER;
137 }
138 *format = -1;
139 if (isClosed()) {
140 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
141 return AMEDIA_ERROR_INVALID_OBJECT;
142 }
143 *format = mFormat;
144 return AMEDIA_OK;
145}
146
147media_status_t
148AImage::getNumPlanes(int32_t* numPlanes) const {
149 if (numPlanes == nullptr) {
150 return AMEDIA_ERROR_INVALID_PARAMETER;
151 }
152 *numPlanes = -1;
153 if (isClosed()) {
154 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
155 return AMEDIA_ERROR_INVALID_OBJECT;
156 }
157 *numPlanes = mNumPlanes;
158 return AMEDIA_OK;
159}
160
161media_status_t
162AImage::getTimestamp(int64_t* timestamp) const {
163 if (timestamp == nullptr) {
164 return AMEDIA_ERROR_INVALID_PARAMETER;
165 }
166 *timestamp = -1;
167 if (isClosed()) {
168 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
169 return AMEDIA_ERROR_INVALID_OBJECT;
170 }
171 *timestamp = mTimestamp;
172 return AMEDIA_OK;
173}
174
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800175media_status_t AImage::lockImage() {
176 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
177 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
178 return AMEDIA_ERROR_INVALID_OBJECT;
179 }
180
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700181 if ((mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800182 ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700183 __FUNCTION__, this, mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800184 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
185 }
186
187 if (mLockedBuffer != nullptr) {
188 // Return immediately if the image has already been locked.
189 return AMEDIA_OK;
190 }
191
192 auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>();
193
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700194 uint64_t grallocUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(mUsage);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800195
196 status_t ret =
Jiwen 'Steve' Caie31bc872017-04-21 17:13:18 -0700197 lockImageFromBuffer(mBuffer, grallocUsage, mBuffer->mFence->dup(), lockedBuffer.get());
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800198 if (ret != OK) {
199 ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret);
200 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
201 }
202
203 ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this);
204 mLockedBuffer = std::move(lockedBuffer);
205
206 return AMEDIA_OK;
207}
208
209media_status_t AImage::unlockImageIfLocked(int* fenceFd) {
210 if (fenceFd == nullptr) {
211 LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__);
212 return AMEDIA_ERROR_INVALID_PARAMETER;
213 }
214
215 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
216 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
217 return AMEDIA_ERROR_INVALID_OBJECT;
218 }
219
220 if (mLockedBuffer == nullptr) {
221 // This image hasn't been locked yet, no need to unlock.
222 *fenceFd = -1;
223 return AMEDIA_OK;
224 }
225
226 // No fence by default.
227 int releaseFenceFd = -1;
228 status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd);
229 if (res != OK) {
230 ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this);
231 *fenceFd = -1;
232 return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE;
233 }
234
235 *fenceFd = releaseFenceFd;
236 return AMEDIA_OK;
237}
238
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800239media_status_t
240AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800241 if (mLockedBuffer == nullptr) {
242 ALOGE("%s: buffer not locked.", __FUNCTION__);
243 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
244 }
245
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800246 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
247 ALOGE("Error: planeIdx %d out of bound [0,%d]",
248 planeIdx, mNumPlanes - 1);
249 return AMEDIA_ERROR_INVALID_PARAMETER;
250 }
251 if (pixelStride == nullptr) {
252 return AMEDIA_ERROR_INVALID_PARAMETER;
253 }
254 if (isClosed()) {
255 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
256 return AMEDIA_ERROR_INVALID_OBJECT;
257 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800258 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800259 switch (fmt) {
260 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800261 *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800262 return AMEDIA_OK;
263 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
264 *pixelStride = (planeIdx == 0) ? 1 : 2;
265 return AMEDIA_OK;
266 case HAL_PIXEL_FORMAT_Y8:
267 *pixelStride = 1;
268 return AMEDIA_OK;
269 case HAL_PIXEL_FORMAT_YV12:
270 *pixelStride = 1;
271 return AMEDIA_OK;
272 case HAL_PIXEL_FORMAT_Y16:
273 case HAL_PIXEL_FORMAT_RAW16:
274 case HAL_PIXEL_FORMAT_RGB_565:
275 // Single plane 16bpp data.
276 *pixelStride = 2;
277 return AMEDIA_OK;
278 case HAL_PIXEL_FORMAT_RGBA_8888:
279 case HAL_PIXEL_FORMAT_RGBX_8888:
280 *pixelStride = 4;
281 return AMEDIA_OK;
282 case HAL_PIXEL_FORMAT_RGB_888:
283 // Single plane, 24bpp.
284 *pixelStride = 3;
285 return AMEDIA_OK;
286 case HAL_PIXEL_FORMAT_BLOB:
287 case HAL_PIXEL_FORMAT_RAW10:
288 case HAL_PIXEL_FORMAT_RAW12:
289 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
290 // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
291 // those are single plane data without pixel stride defined
292 return AMEDIA_ERROR_UNSUPPORTED;
293 default:
294 ALOGE("Pixel format: 0x%x is unsupported", fmt);
295 return AMEDIA_ERROR_UNSUPPORTED;
296 }
297}
298
299media_status_t
300AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800301 if (mLockedBuffer == nullptr) {
302 ALOGE("%s: buffer not locked.", __FUNCTION__);
303 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
304 }
305
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800306 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
307 ALOGE("Error: planeIdx %d out of bound [0,%d]",
308 planeIdx, mNumPlanes - 1);
309 return AMEDIA_ERROR_INVALID_PARAMETER;
310 }
311 if (rowStride == nullptr) {
312 return AMEDIA_ERROR_INVALID_PARAMETER;
313 }
314 if (isClosed()) {
315 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
316 return AMEDIA_ERROR_INVALID_OBJECT;
317 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800318 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800319 switch (fmt) {
320 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800321 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
322 : mLockedBuffer->chromaStride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800323 return AMEDIA_OK;
324 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800325 *rowStride = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800326 return AMEDIA_OK;
327 case HAL_PIXEL_FORMAT_YV12:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800328 if (mLockedBuffer->stride % 16) {
329 ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800330 return AMEDIA_ERROR_UNKNOWN;
331 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800332 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
333 : ALIGN(mLockedBuffer->stride / 2, 16);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800334 return AMEDIA_OK;
335 case HAL_PIXEL_FORMAT_RAW10:
336 case HAL_PIXEL_FORMAT_RAW12:
337 // 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 -0800338 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800339 return AMEDIA_OK;
340 case HAL_PIXEL_FORMAT_Y8:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800341 if (mLockedBuffer->stride % 16) {
342 ALOGE("Stride %d is not 16 pixel aligned!",
343 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800344 return AMEDIA_ERROR_UNKNOWN;
345 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800346 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800347 return AMEDIA_OK;
348 case HAL_PIXEL_FORMAT_Y16:
349 case HAL_PIXEL_FORMAT_RAW16:
350 // In native side, strides are specified in pixels, not in bytes.
351 // Single plane 16bpp bayer data. even width/height,
352 // row stride multiple of 16 pixels (32 bytes)
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800353 if (mLockedBuffer->stride % 16) {
354 ALOGE("Stride %d is not 16 pixel aligned!",
355 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800356 return AMEDIA_ERROR_UNKNOWN;
357 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800358 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800359 return AMEDIA_OK;
360 case HAL_PIXEL_FORMAT_RGB_565:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800361 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800362 return AMEDIA_OK;
363 case HAL_PIXEL_FORMAT_RGBA_8888:
364 case HAL_PIXEL_FORMAT_RGBX_8888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800365 *rowStride = mLockedBuffer->stride * 4;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800366 return AMEDIA_OK;
367 case HAL_PIXEL_FORMAT_RGB_888:
368 // Single plane, 24bpp.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800369 *rowStride = mLockedBuffer->stride * 3;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800370 return AMEDIA_OK;
371 case HAL_PIXEL_FORMAT_BLOB:
372 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
373 // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
374 // no row stride defined
375 return AMEDIA_ERROR_UNSUPPORTED;
376 default:
377 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
378 return AMEDIA_ERROR_UNSUPPORTED;
379 }
380}
381
382uint32_t
383AImage::getJpegSize() const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800384 if (mLockedBuffer == nullptr) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800385 LOG_ALWAYS_FATAL("Error: buffer is null");
386 }
387
388 uint32_t size = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800389 uint32_t width = mLockedBuffer->width;
390 uint8_t* jpegBuffer = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800391
392 // First check for JPEG transport header at the end of the buffer
393 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
394 struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
395 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
396 size = blob->jpeg_size;
397 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
398 }
399
400 // failed to find size, default to whole buffer
401 if (size == 0) {
402 /*
403 * This is a problem because not including the JPEG header
404 * means that in certain rare situations a regular JPEG blob
405 * will be misidentified as having a header, in which case
406 * we will get a garbage size value.
407 */
408 ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
409 __FUNCTION__, width);
410 size = width;
411 }
412
413 return size;
414}
415
416media_status_t
417AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800418 if (mLockedBuffer == nullptr) {
419 ALOGE("%s: buffer not locked.", __FUNCTION__);
420 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
421 }
422
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800423 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
424 ALOGE("Error: planeIdx %d out of bound [0,%d]",
425 planeIdx, mNumPlanes - 1);
426 return AMEDIA_ERROR_INVALID_PARAMETER;
427 }
428 if (data == nullptr || dataLength == nullptr) {
429 return AMEDIA_ERROR_INVALID_PARAMETER;
430 }
431 if (isClosed()) {
432 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
433 return AMEDIA_ERROR_INVALID_OBJECT;
434 }
435
436 uint32_t dataSize, ySize, cSize, cStride;
437 uint8_t* cb = nullptr;
438 uint8_t* cr = nullptr;
439 uint8_t* pData = nullptr;
440 int bytesPerPixel = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800441 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800442
443 switch (fmt) {
444 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800445 pData = (planeIdx == 0) ? mLockedBuffer->data
446 : (planeIdx == 1) ? mLockedBuffer->dataCb
447 : mLockedBuffer->dataCr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800448 // only map until last pixel
449 if (planeIdx == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800450 dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) +
451 mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800452 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800453 dataSize =
454 mLockedBuffer->chromaStride *
455 (mLockedBuffer->height / 2 - 1) +
456 mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) +
457 1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800458 }
459 break;
460 // NV21
461 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800462 cr = mLockedBuffer->data +
463 (mLockedBuffer->stride * mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800464 cb = cr + 1;
465 // only map until last pixel
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800466 ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) +
467 mLockedBuffer->width;
468 cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) +
469 mLockedBuffer->width - 1;
470 pData = (planeIdx == 0) ? mLockedBuffer->data
471 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800472 dataSize = (planeIdx == 0) ? ySize : cSize;
473 break;
474 case HAL_PIXEL_FORMAT_YV12:
475 // Y and C stride need to be 16 pixel aligned.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800476 if (mLockedBuffer->stride % 16) {
477 ALOGE("Stride %d is not 16 pixel aligned!",
478 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800479 return AMEDIA_ERROR_UNKNOWN;
480 }
481
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800482 ySize = mLockedBuffer->stride * mLockedBuffer->height;
483 cStride = ALIGN(mLockedBuffer->stride / 2, 16);
484 cr = mLockedBuffer->data + ySize;
485 cSize = cStride * mLockedBuffer->height / 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800486 cb = cr + cSize;
487
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800488 pData = (planeIdx == 0) ? mLockedBuffer->data
489 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800490 dataSize = (planeIdx == 0) ? ySize : cSize;
491 break;
492 case HAL_PIXEL_FORMAT_Y8:
493 // Single plane, 8bpp.
494
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800495 pData = mLockedBuffer->data;
496 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800497 break;
498 case HAL_PIXEL_FORMAT_Y16:
499 bytesPerPixel = 2;
500
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800501 pData = mLockedBuffer->data;
502 dataSize =
503 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800504 break;
505 case HAL_PIXEL_FORMAT_BLOB:
506 // Used for JPEG data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800507 if (mLockedBuffer->height != 1) {
508 ALOGE("Jpeg should have height value one but got %d",
509 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800510 return AMEDIA_ERROR_UNKNOWN;
511 }
512
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800513 pData = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800514 dataSize = getJpegSize();
515 break;
516 case HAL_PIXEL_FORMAT_RAW16:
517 // Single plane 16bpp bayer data.
518 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800519 pData = mLockedBuffer->data;
520 dataSize =
521 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800522 break;
523 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
524 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800525 if (mLockedBuffer->height != 1) {
526 ALOGE("RAW_OPAQUE should have height value one but got %d",
527 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800528 return AMEDIA_ERROR_UNKNOWN;
529 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800530 pData = mLockedBuffer->data;
531 dataSize = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800532 break;
533 case HAL_PIXEL_FORMAT_RAW10:
534 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800535 if (mLockedBuffer->width % 4) {
536 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800537 return AMEDIA_ERROR_UNKNOWN;
538 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800539 if (mLockedBuffer->height % 2) {
540 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800541 return AMEDIA_ERROR_UNKNOWN;
542 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800543 if (mLockedBuffer->stride < (mLockedBuffer->width * 10 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800544 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800545 mLockedBuffer->stride, mLockedBuffer->width * 10 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800546 return AMEDIA_ERROR_UNKNOWN;
547 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800548 pData = mLockedBuffer->data;
549 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800550 break;
551 case HAL_PIXEL_FORMAT_RAW12:
552 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800553 if (mLockedBuffer->width % 4) {
554 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800555 return AMEDIA_ERROR_UNKNOWN;
556 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800557 if (mLockedBuffer->height % 2) {
558 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800559 return AMEDIA_ERROR_UNKNOWN;
560 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800561 if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800562 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800563 mLockedBuffer->stride, mLockedBuffer->width * 12 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800564 return AMEDIA_ERROR_UNKNOWN;
565 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800566 pData = mLockedBuffer->data;
567 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800568 break;
569 case HAL_PIXEL_FORMAT_RGBA_8888:
570 case HAL_PIXEL_FORMAT_RGBX_8888:
571 // Single plane, 32bpp.
572 bytesPerPixel = 4;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800573 pData = mLockedBuffer->data;
574 dataSize =
575 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800576 break;
577 case HAL_PIXEL_FORMAT_RGB_565:
578 // Single plane, 16bpp.
579 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800580 pData = mLockedBuffer->data;
581 dataSize =
582 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800583 break;
584 case HAL_PIXEL_FORMAT_RGB_888:
585 // Single plane, 24bpp.
586 bytesPerPixel = 3;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800587 pData = mLockedBuffer->data;
588 dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800589 break;
590 default:
591 ALOGE("Pixel format: 0x%x is unsupported", fmt);
592 return AMEDIA_ERROR_UNSUPPORTED;
593 }
594
595 *data = pData;
596 *dataLength = dataSize;
597 return AMEDIA_OK;
598}
599
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800600media_status_t
601AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const {
602 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
603 ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this);
604 return AMEDIA_ERROR_INVALID_OBJECT;
605 }
606
607 // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast.
608 *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get());
609 return AMEDIA_OK;
610}
611
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800612EXPORT
613void AImage_delete(AImage* image) {
614 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800615 AImage_deleteAsync(image, -1);
616 return;
617}
618
619EXPORT
620void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
621 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800622 if (image != nullptr) {
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800623 image->lockReader();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800624 image->close(releaseFenceFd);
Yin-Chia Yehb29fce72017-11-06 17:16:22 -0800625 image->unlockReader();
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}