blob: 95fdf36b9de249159d826e094b629df3caf93c34 [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' Caie1689962017-02-20 16:59:05 -080034AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage0, uint64_t usage1,
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080035 BufferItem* buffer, int64_t timestamp,
Yin-Chia Yehc3603822016-01-18 22:11:19 -080036 int32_t width, int32_t height, int32_t numPlanes) :
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080037 mReader(reader), mFormat(format), mUsage0(usage0), mUsage1(usage1),
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -080038 mBuffer(buffer), mLockedBuffer(nullptr), mTimestamp(timestamp),
Yin-Chia Yehc3603822016-01-18 22:11:19 -080039 mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
40}
41
42// Can only be called by free() with mLock hold
43AImage::~AImage() {
44 if (!mIsClosed) {
45 LOG_ALWAYS_FATAL(
46 "Error: AImage %p is deleted before returning buffer to AImageReader!", this);
47 }
48}
49
50bool
51AImage::isClosed() const {
52 Mutex::Autolock _l(mLock);
53 return mIsClosed;
54}
55
56void
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080057AImage::close(int releaseFenceFd) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -080058 Mutex::Autolock _l(mLock);
59 if (mIsClosed) {
60 return;
61 }
62 sp<AImageReader> reader = mReader.promote();
63 if (reader == nullptr) {
64 LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
65 return;
66 }
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -080067 reader->releaseImageLocked(this, releaseFenceFd);
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' Caie1689962017-02-20 16:59:05 -0800181 if ((mUsage0 & AHARDWAREBUFFER_USAGE0_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' Caie1689962017-02-20 16:59:05 -0800183 __FUNCTION__, this, mUsage0);
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
194 uint64_t producerUsage;
195 uint64_t consumerUsage;
196 android_hardware_HardwareBuffer_convertToGrallocUsageBits(
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800197 &producerUsage, &consumerUsage, mUsage0, mUsage1);
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800198
199 status_t ret =
200 lockImageFromBuffer(mBuffer, consumerUsage, mBuffer->mFence->dup(), lockedBuffer.get());
201 if (ret != OK) {
202 ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret);
203 return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
204 }
205
206 ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this);
207 mLockedBuffer = std::move(lockedBuffer);
208
209 return AMEDIA_OK;
210}
211
212media_status_t AImage::unlockImageIfLocked(int* fenceFd) {
213 if (fenceFd == nullptr) {
214 LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__);
215 return AMEDIA_ERROR_INVALID_PARAMETER;
216 }
217
218 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
219 LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
220 return AMEDIA_ERROR_INVALID_OBJECT;
221 }
222
223 if (mLockedBuffer == nullptr) {
224 // This image hasn't been locked yet, no need to unlock.
225 *fenceFd = -1;
226 return AMEDIA_OK;
227 }
228
229 // No fence by default.
230 int releaseFenceFd = -1;
231 status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd);
232 if (res != OK) {
233 ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this);
234 *fenceFd = -1;
235 return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE;
236 }
237
238 *fenceFd = releaseFenceFd;
239 return AMEDIA_OK;
240}
241
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800242media_status_t
243AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800244 if (mLockedBuffer == nullptr) {
245 ALOGE("%s: buffer not locked.", __FUNCTION__);
246 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
247 }
248
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800249 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
250 ALOGE("Error: planeIdx %d out of bound [0,%d]",
251 planeIdx, mNumPlanes - 1);
252 return AMEDIA_ERROR_INVALID_PARAMETER;
253 }
254 if (pixelStride == nullptr) {
255 return AMEDIA_ERROR_INVALID_PARAMETER;
256 }
257 if (isClosed()) {
258 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
259 return AMEDIA_ERROR_INVALID_OBJECT;
260 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800261 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800262 switch (fmt) {
263 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800264 *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800265 return AMEDIA_OK;
266 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
267 *pixelStride = (planeIdx == 0) ? 1 : 2;
268 return AMEDIA_OK;
269 case HAL_PIXEL_FORMAT_Y8:
270 *pixelStride = 1;
271 return AMEDIA_OK;
272 case HAL_PIXEL_FORMAT_YV12:
273 *pixelStride = 1;
274 return AMEDIA_OK;
275 case HAL_PIXEL_FORMAT_Y16:
276 case HAL_PIXEL_FORMAT_RAW16:
277 case HAL_PIXEL_FORMAT_RGB_565:
278 // Single plane 16bpp data.
279 *pixelStride = 2;
280 return AMEDIA_OK;
281 case HAL_PIXEL_FORMAT_RGBA_8888:
282 case HAL_PIXEL_FORMAT_RGBX_8888:
283 *pixelStride = 4;
284 return AMEDIA_OK;
285 case HAL_PIXEL_FORMAT_RGB_888:
286 // Single plane, 24bpp.
287 *pixelStride = 3;
288 return AMEDIA_OK;
289 case HAL_PIXEL_FORMAT_BLOB:
290 case HAL_PIXEL_FORMAT_RAW10:
291 case HAL_PIXEL_FORMAT_RAW12:
292 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
293 // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
294 // those are single plane data without pixel stride defined
295 return AMEDIA_ERROR_UNSUPPORTED;
296 default:
297 ALOGE("Pixel format: 0x%x is unsupported", fmt);
298 return AMEDIA_ERROR_UNSUPPORTED;
299 }
300}
301
302media_status_t
303AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800304 if (mLockedBuffer == nullptr) {
305 ALOGE("%s: buffer not locked.", __FUNCTION__);
306 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
307 }
308
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800309 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
310 ALOGE("Error: planeIdx %d out of bound [0,%d]",
311 planeIdx, mNumPlanes - 1);
312 return AMEDIA_ERROR_INVALID_PARAMETER;
313 }
314 if (rowStride == nullptr) {
315 return AMEDIA_ERROR_INVALID_PARAMETER;
316 }
317 if (isClosed()) {
318 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
319 return AMEDIA_ERROR_INVALID_OBJECT;
320 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800321 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800322 switch (fmt) {
323 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800324 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
325 : mLockedBuffer->chromaStride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800326 return AMEDIA_OK;
327 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800328 *rowStride = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800329 return AMEDIA_OK;
330 case HAL_PIXEL_FORMAT_YV12:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800331 if (mLockedBuffer->stride % 16) {
332 ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800333 return AMEDIA_ERROR_UNKNOWN;
334 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800335 *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
336 : ALIGN(mLockedBuffer->stride / 2, 16);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800337 return AMEDIA_OK;
338 case HAL_PIXEL_FORMAT_RAW10:
339 case HAL_PIXEL_FORMAT_RAW12:
340 // 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 -0800341 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800342 return AMEDIA_OK;
343 case HAL_PIXEL_FORMAT_Y8:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800344 if (mLockedBuffer->stride % 16) {
345 ALOGE("Stride %d is not 16 pixel aligned!",
346 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800347 return AMEDIA_ERROR_UNKNOWN;
348 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800349 *rowStride = mLockedBuffer->stride;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800350 return AMEDIA_OK;
351 case HAL_PIXEL_FORMAT_Y16:
352 case HAL_PIXEL_FORMAT_RAW16:
353 // In native side, strides are specified in pixels, not in bytes.
354 // Single plane 16bpp bayer data. even width/height,
355 // row stride multiple of 16 pixels (32 bytes)
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800356 if (mLockedBuffer->stride % 16) {
357 ALOGE("Stride %d is not 16 pixel aligned!",
358 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800359 return AMEDIA_ERROR_UNKNOWN;
360 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800361 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800362 return AMEDIA_OK;
363 case HAL_PIXEL_FORMAT_RGB_565:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800364 *rowStride = mLockedBuffer->stride * 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800365 return AMEDIA_OK;
366 case HAL_PIXEL_FORMAT_RGBA_8888:
367 case HAL_PIXEL_FORMAT_RGBX_8888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800368 *rowStride = mLockedBuffer->stride * 4;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800369 return AMEDIA_OK;
370 case HAL_PIXEL_FORMAT_RGB_888:
371 // Single plane, 24bpp.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800372 *rowStride = mLockedBuffer->stride * 3;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800373 return AMEDIA_OK;
374 case HAL_PIXEL_FORMAT_BLOB:
375 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
376 // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
377 // no row stride defined
378 return AMEDIA_ERROR_UNSUPPORTED;
379 default:
380 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
381 return AMEDIA_ERROR_UNSUPPORTED;
382 }
383}
384
385uint32_t
386AImage::getJpegSize() const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800387 if (mLockedBuffer == nullptr) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800388 LOG_ALWAYS_FATAL("Error: buffer is null");
389 }
390
391 uint32_t size = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800392 uint32_t width = mLockedBuffer->width;
393 uint8_t* jpegBuffer = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800394
395 // First check for JPEG transport header at the end of the buffer
396 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
397 struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
398 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
399 size = blob->jpeg_size;
400 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
401 }
402
403 // failed to find size, default to whole buffer
404 if (size == 0) {
405 /*
406 * This is a problem because not including the JPEG header
407 * means that in certain rare situations a regular JPEG blob
408 * will be misidentified as having a header, in which case
409 * we will get a garbage size value.
410 */
411 ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
412 __FUNCTION__, width);
413 size = width;
414 }
415
416 return size;
417}
418
419media_status_t
420AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800421 if (mLockedBuffer == nullptr) {
422 ALOGE("%s: buffer not locked.", __FUNCTION__);
423 return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
424 }
425
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800426 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
427 ALOGE("Error: planeIdx %d out of bound [0,%d]",
428 planeIdx, mNumPlanes - 1);
429 return AMEDIA_ERROR_INVALID_PARAMETER;
430 }
431 if (data == nullptr || dataLength == nullptr) {
432 return AMEDIA_ERROR_INVALID_PARAMETER;
433 }
434 if (isClosed()) {
435 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
436 return AMEDIA_ERROR_INVALID_OBJECT;
437 }
438
439 uint32_t dataSize, ySize, cSize, cStride;
440 uint8_t* cb = nullptr;
441 uint8_t* cr = nullptr;
442 uint8_t* pData = nullptr;
443 int bytesPerPixel = 0;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800444 int32_t fmt = mLockedBuffer->flexFormat;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800445
446 switch (fmt) {
447 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800448 pData = (planeIdx == 0) ? mLockedBuffer->data
449 : (planeIdx == 1) ? mLockedBuffer->dataCb
450 : mLockedBuffer->dataCr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800451 // only map until last pixel
452 if (planeIdx == 0) {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800453 dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) +
454 mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800455 } else {
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800456 dataSize =
457 mLockedBuffer->chromaStride *
458 (mLockedBuffer->height / 2 - 1) +
459 mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) +
460 1;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800461 }
462 break;
463 // NV21
464 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800465 cr = mLockedBuffer->data +
466 (mLockedBuffer->stride * mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800467 cb = cr + 1;
468 // only map until last pixel
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800469 ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) +
470 mLockedBuffer->width;
471 cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) +
472 mLockedBuffer->width - 1;
473 pData = (planeIdx == 0) ? mLockedBuffer->data
474 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800475 dataSize = (planeIdx == 0) ? ySize : cSize;
476 break;
477 case HAL_PIXEL_FORMAT_YV12:
478 // Y and C stride need to be 16 pixel aligned.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800479 if (mLockedBuffer->stride % 16) {
480 ALOGE("Stride %d is not 16 pixel aligned!",
481 mLockedBuffer->stride);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800482 return AMEDIA_ERROR_UNKNOWN;
483 }
484
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800485 ySize = mLockedBuffer->stride * mLockedBuffer->height;
486 cStride = ALIGN(mLockedBuffer->stride / 2, 16);
487 cr = mLockedBuffer->data + ySize;
488 cSize = cStride * mLockedBuffer->height / 2;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800489 cb = cr + cSize;
490
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800491 pData = (planeIdx == 0) ? mLockedBuffer->data
492 : (planeIdx == 1) ? cb : cr;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800493 dataSize = (planeIdx == 0) ? ySize : cSize;
494 break;
495 case HAL_PIXEL_FORMAT_Y8:
496 // Single plane, 8bpp.
497
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800498 pData = mLockedBuffer->data;
499 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800500 break;
501 case HAL_PIXEL_FORMAT_Y16:
502 bytesPerPixel = 2;
503
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800504 pData = mLockedBuffer->data;
505 dataSize =
506 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800507 break;
508 case HAL_PIXEL_FORMAT_BLOB:
509 // Used for JPEG data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800510 if (mLockedBuffer->height != 1) {
511 ALOGE("Jpeg should have height value one but got %d",
512 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800513 return AMEDIA_ERROR_UNKNOWN;
514 }
515
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800516 pData = mLockedBuffer->data;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800517 dataSize = getJpegSize();
518 break;
519 case HAL_PIXEL_FORMAT_RAW16:
520 // Single plane 16bpp bayer data.
521 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800522 pData = mLockedBuffer->data;
523 dataSize =
524 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800525 break;
526 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
527 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800528 if (mLockedBuffer->height != 1) {
529 ALOGE("RAW_OPAQUE should have height value one but got %d",
530 mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800531 return AMEDIA_ERROR_UNKNOWN;
532 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800533 pData = mLockedBuffer->data;
534 dataSize = mLockedBuffer->width;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800535 break;
536 case HAL_PIXEL_FORMAT_RAW10:
537 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800538 if (mLockedBuffer->width % 4) {
539 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
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->height % 2) {
543 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800544 return AMEDIA_ERROR_UNKNOWN;
545 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800546 if (mLockedBuffer->stride < (mLockedBuffer->width * 10 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800547 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800548 mLockedBuffer->stride, mLockedBuffer->width * 10 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800549 return AMEDIA_ERROR_UNKNOWN;
550 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800551 pData = mLockedBuffer->data;
552 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800553 break;
554 case HAL_PIXEL_FORMAT_RAW12:
555 // Single plane 10bpp bayer data.
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800556 if (mLockedBuffer->width % 4) {
557 ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
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->height % 2) {
561 ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800562 return AMEDIA_ERROR_UNKNOWN;
563 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800564 if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) {
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800565 ALOGE("stride (%d) should be at least %d",
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800566 mLockedBuffer->stride, mLockedBuffer->width * 12 / 8);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800567 return AMEDIA_ERROR_UNKNOWN;
568 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800569 pData = mLockedBuffer->data;
570 dataSize = mLockedBuffer->stride * mLockedBuffer->height;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800571 break;
572 case HAL_PIXEL_FORMAT_RGBA_8888:
573 case HAL_PIXEL_FORMAT_RGBX_8888:
574 // Single plane, 32bpp.
575 bytesPerPixel = 4;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800576 pData = mLockedBuffer->data;
577 dataSize =
578 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800579 break;
580 case HAL_PIXEL_FORMAT_RGB_565:
581 // Single plane, 16bpp.
582 bytesPerPixel = 2;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800583 pData = mLockedBuffer->data;
584 dataSize =
585 mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800586 break;
587 case HAL_PIXEL_FORMAT_RGB_888:
588 // Single plane, 24bpp.
589 bytesPerPixel = 3;
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800590 pData = mLockedBuffer->data;
591 dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800592 break;
593 default:
594 ALOGE("Pixel format: 0x%x is unsupported", fmt);
595 return AMEDIA_ERROR_UNSUPPORTED;
596 }
597
598 *data = pData;
599 *dataLength = dataSize;
600 return AMEDIA_OK;
601}
602
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800603media_status_t
604AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const {
605 if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
606 ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this);
607 return AMEDIA_ERROR_INVALID_OBJECT;
608 }
609
610 // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast.
611 *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get());
612 return AMEDIA_OK;
613}
614
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800615EXPORT
616void AImage_delete(AImage* image) {
617 ALOGV("%s", __FUNCTION__);
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800618 AImage_deleteAsync(image, -1);
619 return;
620}
621
622EXPORT
623void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
624 ALOGV("%s", __FUNCTION__);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800625 if (image != nullptr) {
626 image->lockReader();
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800627 image->close(releaseFenceFd);
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800628 image->unlockReader();
629 if (!image->isClosed()) {
630 LOG_ALWAYS_FATAL("Image close failed!");
631 }
632 image->free();
633 }
634 return;
635}
636
637EXPORT
638media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
639 ALOGV("%s", __FUNCTION__);
640 if (image == nullptr || width == nullptr) {
641 ALOGE("%s: bad argument. image %p width %p",
642 __FUNCTION__, image, width);
643 return AMEDIA_ERROR_INVALID_PARAMETER;
644 }
645 return image->getWidth(width);
646}
647
648EXPORT
649media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
650 ALOGV("%s", __FUNCTION__);
651 if (image == nullptr || height == nullptr) {
652 ALOGE("%s: bad argument. image %p height %p",
653 __FUNCTION__, image, height);
654 return AMEDIA_ERROR_INVALID_PARAMETER;
655 }
656 return image->getHeight(height);
657}
658
659EXPORT
660media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
661 ALOGV("%s", __FUNCTION__);
662 if (image == nullptr || format == nullptr) {
663 ALOGE("%s: bad argument. image %p format %p",
664 __FUNCTION__, image, format);
665 return AMEDIA_ERROR_INVALID_PARAMETER;
666 }
667 return image->getFormat(format);
668}
669
670EXPORT
671media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
672 ALOGV("%s", __FUNCTION__);
673 if (image == nullptr || rect == nullptr) {
674 ALOGE("%s: bad argument. image %p rect %p",
675 __FUNCTION__, image, rect);
676 return AMEDIA_ERROR_INVALID_PARAMETER;
677 }
678 // For now AImage only supports camera outputs where cropRect is always full window
679 int32_t width = -1;
680 media_status_t ret = image->getWidth(&width);
681 if (ret != AMEDIA_OK) {
682 return ret;
683 }
684 int32_t height = -1;
685 ret = image->getHeight(&height);
686 if (ret != AMEDIA_OK) {
687 return ret;
688 }
689 rect->left = 0;
690 rect->top = 0;
691 rect->right = width;
692 rect->bottom = height;
693 return AMEDIA_OK;
694}
695
696EXPORT
697media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
698 ALOGV("%s", __FUNCTION__);
699 if (image == nullptr || timestampNs == nullptr) {
700 ALOGE("%s: bad argument. image %p timestampNs %p",
701 __FUNCTION__, image, timestampNs);
702 return AMEDIA_ERROR_INVALID_PARAMETER;
703 }
704 return image->getTimestamp(timestampNs);
705}
706
707EXPORT
708media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
709 ALOGV("%s", __FUNCTION__);
710 if (image == nullptr || numPlanes == nullptr) {
711 ALOGE("%s: bad argument. image %p numPlanes %p",
712 __FUNCTION__, image, numPlanes);
713 return AMEDIA_ERROR_INVALID_PARAMETER;
714 }
715 return image->getNumPlanes(numPlanes);
716}
717
718EXPORT
719media_status_t AImage_getPlanePixelStride(
720 const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
721 ALOGV("%s", __FUNCTION__);
722 if (image == nullptr || pixelStride == nullptr) {
723 ALOGE("%s: bad argument. image %p pixelStride %p",
724 __FUNCTION__, image, pixelStride);
725 return AMEDIA_ERROR_INVALID_PARAMETER;
726 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800727 media_status_t ret = const_cast<AImage*>(image)->lockImage();
728 if (ret != AMEDIA_OK) {
729 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
730 __FUNCTION__, image, ret);
731 return ret;
732 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800733 return image->getPlanePixelStride(planeIdx, pixelStride);
734}
735
736EXPORT
737media_status_t AImage_getPlaneRowStride(
738 const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
739 ALOGV("%s", __FUNCTION__);
740 if (image == nullptr || rowStride == nullptr) {
741 ALOGE("%s: bad argument. image %p rowStride %p",
742 __FUNCTION__, image, rowStride);
743 return AMEDIA_ERROR_INVALID_PARAMETER;
744 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800745 media_status_t ret = const_cast<AImage*>(image)->lockImage();
746 if (ret != AMEDIA_OK) {
747 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
748 __FUNCTION__, image, ret);
749 return ret;
750 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800751 return image->getPlaneRowStride(planeIdx, rowStride);
752}
753
754EXPORT
755media_status_t AImage_getPlaneData(
756 const AImage* image, int planeIdx,
757 /*out*/uint8_t** data, /*out*/int* dataLength) {
758 ALOGV("%s", __FUNCTION__);
759 if (image == nullptr || data == nullptr || dataLength == nullptr) {
760 ALOGE("%s: bad argument. image %p data %p dataLength %p",
761 __FUNCTION__, image, data, dataLength);
762 return AMEDIA_ERROR_INVALID_PARAMETER;
763 }
Jiwen 'Steve' Cai2f1a4732017-02-04 17:31:55 -0800764 media_status_t ret = const_cast<AImage*>(image)->lockImage();
765 if (ret != AMEDIA_OK) {
766 ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
767 __FUNCTION__, image, ret);
768 return ret;
769 }
Yin-Chia Yehc3603822016-01-18 22:11:19 -0800770 return image->getPlaneData(planeIdx, data, dataLength);
771}
Jiwen 'Steve' Caie1689962017-02-20 16:59:05 -0800772
773EXPORT
774media_status_t AImage_getHardwareBuffer(
775 const AImage* image, /*out*/AHardwareBuffer** buffer) {
776 ALOGV("%s", __FUNCTION__);
777
778 if (image == nullptr || buffer == nullptr) {
779 ALOGE("%s: bad argument. image %p buffer %p", __FUNCTION__, image, buffer);
780 return AMEDIA_ERROR_INVALID_PARAMETER;
781 }
782 return image->getHardwareBuffer(buffer);
783}