1 /*
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
25 #include <utils/Log.h>
26 #include "hardware/camera3.h"
27
28 using namespace android;
29
30 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
31
AImage(AImageReader * reader,int32_t format,CpuConsumer::LockedBuffer * buffer,int64_t timestamp,int32_t width,int32_t height,int32_t numPlanes)32 AImage::AImage(AImageReader* reader, int32_t format,
33 CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
34 int32_t width, int32_t height, int32_t numPlanes) :
35 mReader(reader), mFormat(format),
36 mBuffer(buffer), mTimestamp(timestamp),
37 mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
38 }
39
40 // Can only be called by free() with mLock hold
~AImage()41 AImage::~AImage() {
42 if (!mIsClosed) {
43 LOG_ALWAYS_FATAL(
44 "Error: AImage %p is deleted before returning buffer to AImageReader!", this);
45 }
46 }
47
48 bool
isClosed() const49 AImage::isClosed() const {
50 Mutex::Autolock _l(mLock);
51 return mIsClosed;
52 }
53
54 void
close()55 AImage::close() {
56 Mutex::Autolock _l(mLock);
57 if (mIsClosed) {
58 return;
59 }
60 sp<AImageReader> reader = mReader.promote();
61 if (reader == nullptr) {
62 LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
63 return;
64 }
65 reader->releaseImageLocked(this);
66 // Should have been set to nullptr in releaseImageLocked
67 // Set to nullptr here for extra safety only
68 mBuffer = nullptr;
69 mIsClosed = true;
70 }
71
72 void
free()73 AImage::free() {
74 if (!isClosed()) {
75 ALOGE("Cannot free AImage before close!");
76 return;
77 }
78 Mutex::Autolock _l(mLock);
79 delete this;
80 }
81
82 void
lockReader() const83 AImage::lockReader() const {
84 sp<AImageReader> reader = mReader.promote();
85 if (reader == nullptr) {
86 // Reader has been closed
87 return;
88 }
89 reader->mLock.lock();
90 }
91
92 void
unlockReader() const93 AImage::unlockReader() const {
94 sp<AImageReader> reader = mReader.promote();
95 if (reader == nullptr) {
96 // Reader has been closed
97 return;
98 }
99 reader->mLock.unlock();
100 }
101
102 media_status_t
getWidth(int32_t * width) const103 AImage::getWidth(int32_t* width) const {
104 if (width == nullptr) {
105 return AMEDIA_ERROR_INVALID_PARAMETER;
106 }
107 *width = -1;
108 if (isClosed()) {
109 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
110 return AMEDIA_ERROR_INVALID_OBJECT;
111 }
112 *width = mWidth;
113 return AMEDIA_OK;
114 }
115
116 media_status_t
getHeight(int32_t * height) const117 AImage::getHeight(int32_t* height) const {
118 if (height == nullptr) {
119 return AMEDIA_ERROR_INVALID_PARAMETER;
120 }
121 *height = -1;
122 if (isClosed()) {
123 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
124 return AMEDIA_ERROR_INVALID_OBJECT;
125 }
126 *height = mHeight;
127 return AMEDIA_OK;
128 }
129
130 media_status_t
getFormat(int32_t * format) const131 AImage::getFormat(int32_t* format) const {
132 if (format == nullptr) {
133 return AMEDIA_ERROR_INVALID_PARAMETER;
134 }
135 *format = -1;
136 if (isClosed()) {
137 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
138 return AMEDIA_ERROR_INVALID_OBJECT;
139 }
140 *format = mFormat;
141 return AMEDIA_OK;
142 }
143
144 media_status_t
getNumPlanes(int32_t * numPlanes) const145 AImage::getNumPlanes(int32_t* numPlanes) const {
146 if (numPlanes == nullptr) {
147 return AMEDIA_ERROR_INVALID_PARAMETER;
148 }
149 *numPlanes = -1;
150 if (isClosed()) {
151 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
152 return AMEDIA_ERROR_INVALID_OBJECT;
153 }
154 *numPlanes = mNumPlanes;
155 return AMEDIA_OK;
156 }
157
158 media_status_t
getTimestamp(int64_t * timestamp) const159 AImage::getTimestamp(int64_t* timestamp) const {
160 if (timestamp == nullptr) {
161 return AMEDIA_ERROR_INVALID_PARAMETER;
162 }
163 *timestamp = -1;
164 if (isClosed()) {
165 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
166 return AMEDIA_ERROR_INVALID_OBJECT;
167 }
168 *timestamp = mTimestamp;
169 return AMEDIA_OK;
170 }
171
172 media_status_t
getPlanePixelStride(int planeIdx,int32_t * pixelStride) const173 AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
174 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
175 ALOGE("Error: planeIdx %d out of bound [0,%d]",
176 planeIdx, mNumPlanes - 1);
177 return AMEDIA_ERROR_INVALID_PARAMETER;
178 }
179 if (pixelStride == nullptr) {
180 return AMEDIA_ERROR_INVALID_PARAMETER;
181 }
182 if (isClosed()) {
183 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
184 return AMEDIA_ERROR_INVALID_OBJECT;
185 }
186 int32_t fmt = mBuffer->flexFormat;
187 switch (fmt) {
188 case HAL_PIXEL_FORMAT_YCbCr_420_888:
189 *pixelStride = (planeIdx == 0) ? 1 : mBuffer->chromaStep;
190 return AMEDIA_OK;
191 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
192 *pixelStride = (planeIdx == 0) ? 1 : 2;
193 return AMEDIA_OK;
194 case HAL_PIXEL_FORMAT_Y8:
195 *pixelStride = 1;
196 return AMEDIA_OK;
197 case HAL_PIXEL_FORMAT_YV12:
198 *pixelStride = 1;
199 return AMEDIA_OK;
200 case HAL_PIXEL_FORMAT_Y16:
201 case HAL_PIXEL_FORMAT_RAW16:
202 case HAL_PIXEL_FORMAT_RGB_565:
203 // Single plane 16bpp data.
204 *pixelStride = 2;
205 return AMEDIA_OK;
206 case HAL_PIXEL_FORMAT_RGBA_8888:
207 case HAL_PIXEL_FORMAT_RGBX_8888:
208 *pixelStride = 4;
209 return AMEDIA_OK;
210 case HAL_PIXEL_FORMAT_RGB_888:
211 // Single plane, 24bpp.
212 *pixelStride = 3;
213 return AMEDIA_OK;
214 case HAL_PIXEL_FORMAT_BLOB:
215 case HAL_PIXEL_FORMAT_RAW10:
216 case HAL_PIXEL_FORMAT_RAW12:
217 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
218 // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
219 // those are single plane data without pixel stride defined
220 return AMEDIA_ERROR_UNSUPPORTED;
221 default:
222 ALOGE("Pixel format: 0x%x is unsupported", fmt);
223 return AMEDIA_ERROR_UNSUPPORTED;
224 }
225 }
226
227 media_status_t
getPlaneRowStride(int planeIdx,int32_t * rowStride) const228 AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
229 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
230 ALOGE("Error: planeIdx %d out of bound [0,%d]",
231 planeIdx, mNumPlanes - 1);
232 return AMEDIA_ERROR_INVALID_PARAMETER;
233 }
234 if (rowStride == nullptr) {
235 return AMEDIA_ERROR_INVALID_PARAMETER;
236 }
237 if (isClosed()) {
238 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
239 return AMEDIA_ERROR_INVALID_OBJECT;
240 }
241 int32_t fmt = mBuffer->flexFormat;
242 switch (fmt) {
243 case HAL_PIXEL_FORMAT_YCbCr_420_888:
244 *rowStride = (planeIdx == 0) ? mBuffer->stride : mBuffer->chromaStride;
245 return AMEDIA_OK;
246 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
247 *rowStride = mBuffer->width;
248 return AMEDIA_OK;
249 case HAL_PIXEL_FORMAT_YV12:
250 if (mBuffer->stride % 16) {
251 ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
252 return AMEDIA_ERROR_UNKNOWN;
253 }
254 *rowStride = (planeIdx == 0) ? mBuffer->stride : ALIGN(mBuffer->stride / 2, 16);
255 return AMEDIA_OK;
256 case HAL_PIXEL_FORMAT_RAW10:
257 case HAL_PIXEL_FORMAT_RAW12:
258 // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
259 *rowStride = mBuffer->stride;
260 return AMEDIA_OK;
261 case HAL_PIXEL_FORMAT_Y8:
262 if (mBuffer->stride % 16) {
263 ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
264 return AMEDIA_ERROR_UNKNOWN;
265 }
266 *rowStride = mBuffer->stride;
267 return AMEDIA_OK;
268 case HAL_PIXEL_FORMAT_Y16:
269 case HAL_PIXEL_FORMAT_RAW16:
270 // In native side, strides are specified in pixels, not in bytes.
271 // Single plane 16bpp bayer data. even width/height,
272 // row stride multiple of 16 pixels (32 bytes)
273 if (mBuffer->stride % 16) {
274 ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
275 return AMEDIA_ERROR_UNKNOWN;
276 }
277 *rowStride = mBuffer->stride * 2;
278 return AMEDIA_OK;
279 case HAL_PIXEL_FORMAT_RGB_565:
280 *rowStride = mBuffer->stride * 2;
281 return AMEDIA_OK;
282 case HAL_PIXEL_FORMAT_RGBA_8888:
283 case HAL_PIXEL_FORMAT_RGBX_8888:
284 *rowStride = mBuffer->stride * 4;
285 return AMEDIA_OK;
286 case HAL_PIXEL_FORMAT_RGB_888:
287 // Single plane, 24bpp.
288 *rowStride = mBuffer->stride * 3;
289 return AMEDIA_OK;
290 case HAL_PIXEL_FORMAT_BLOB:
291 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
292 // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
293 // no row stride defined
294 return AMEDIA_ERROR_UNSUPPORTED;
295 default:
296 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
297 return AMEDIA_ERROR_UNSUPPORTED;
298 }
299 }
300
301 uint32_t
getJpegSize() const302 AImage::getJpegSize() const {
303 if (mBuffer == nullptr) {
304 LOG_ALWAYS_FATAL("Error: buffer is null");
305 }
306
307 uint32_t size = 0;
308 uint32_t width = mBuffer->width;
309 uint8_t* jpegBuffer = mBuffer->data;
310
311 // First check for JPEG transport header at the end of the buffer
312 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
313 struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
314 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
315 size = blob->jpeg_size;
316 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
317 }
318
319 // failed to find size, default to whole buffer
320 if (size == 0) {
321 /*
322 * This is a problem because not including the JPEG header
323 * means that in certain rare situations a regular JPEG blob
324 * will be misidentified as having a header, in which case
325 * we will get a garbage size value.
326 */
327 ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
328 __FUNCTION__, width);
329 size = width;
330 }
331
332 return size;
333 }
334
335 media_status_t
getPlaneData(int planeIdx,uint8_t ** data,int * dataLength) const336 AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
337 if (planeIdx < 0 || planeIdx >= mNumPlanes) {
338 ALOGE("Error: planeIdx %d out of bound [0,%d]",
339 planeIdx, mNumPlanes - 1);
340 return AMEDIA_ERROR_INVALID_PARAMETER;
341 }
342 if (data == nullptr || dataLength == nullptr) {
343 return AMEDIA_ERROR_INVALID_PARAMETER;
344 }
345 if (isClosed()) {
346 ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
347 return AMEDIA_ERROR_INVALID_OBJECT;
348 }
349
350 uint32_t dataSize, ySize, cSize, cStride;
351 uint8_t* cb = nullptr;
352 uint8_t* cr = nullptr;
353 uint8_t* pData = nullptr;
354 int bytesPerPixel = 0;
355 int32_t fmt = mBuffer->flexFormat;
356
357 switch (fmt) {
358 case HAL_PIXEL_FORMAT_YCbCr_420_888:
359 pData = (planeIdx == 0) ? mBuffer->data :
360 (planeIdx == 1) ? mBuffer->dataCb : mBuffer->dataCr;
361 // only map until last pixel
362 if (planeIdx == 0) {
363 dataSize = mBuffer->stride * (mBuffer->height - 1) + mBuffer->width;
364 } else {
365 dataSize = mBuffer->chromaStride * (mBuffer->height / 2 - 1) +
366 mBuffer->chromaStep * (mBuffer->width / 2 - 1) + 1;
367 }
368 break;
369 // NV21
370 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
371 cr = mBuffer->data + (mBuffer->stride * mBuffer->height);
372 cb = cr + 1;
373 // only map until last pixel
374 ySize = mBuffer->width * (mBuffer->height - 1) + mBuffer->width;
375 cSize = mBuffer->width * (mBuffer->height / 2 - 1) + mBuffer->width - 1;
376
377 pData = (planeIdx == 0) ? mBuffer->data :
378 (planeIdx == 1) ? cb : cr;
379 dataSize = (planeIdx == 0) ? ySize : cSize;
380 break;
381 case HAL_PIXEL_FORMAT_YV12:
382 // Y and C stride need to be 16 pixel aligned.
383 if (mBuffer->stride % 16) {
384 ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
385 return AMEDIA_ERROR_UNKNOWN;
386 }
387
388 ySize = mBuffer->stride * mBuffer->height;
389 cStride = ALIGN(mBuffer->stride / 2, 16);
390 cr = mBuffer->data + ySize;
391 cSize = cStride * mBuffer->height / 2;
392 cb = cr + cSize;
393
394 pData = (planeIdx == 0) ? mBuffer->data :
395 (planeIdx == 1) ? cb : cr;
396 dataSize = (planeIdx == 0) ? ySize : cSize;
397 break;
398 case HAL_PIXEL_FORMAT_Y8:
399 // Single plane, 8bpp.
400
401 pData = mBuffer->data;
402 dataSize = mBuffer->stride * mBuffer->height;
403 break;
404 case HAL_PIXEL_FORMAT_Y16:
405 bytesPerPixel = 2;
406
407 pData = mBuffer->data;
408 dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
409 break;
410 case HAL_PIXEL_FORMAT_BLOB:
411 // Used for JPEG data, height must be 1, width == size, single plane.
412 if (mBuffer->height != 1) {
413 ALOGE("Jpeg should have height value one but got %d", mBuffer->height);
414 return AMEDIA_ERROR_UNKNOWN;
415 }
416
417 pData = mBuffer->data;
418 dataSize = getJpegSize();
419 break;
420 case HAL_PIXEL_FORMAT_RAW16:
421 // Single plane 16bpp bayer data.
422 bytesPerPixel = 2;
423 pData = mBuffer->data;
424 dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
425 break;
426 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
427 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
428 if (mBuffer->height != 1) {
429 ALOGE("RAW_OPAQUE should have height value one but got %d", mBuffer->height);
430 return AMEDIA_ERROR_UNKNOWN;
431 }
432 pData = mBuffer->data;
433 dataSize = mBuffer->width;
434 break;
435 case HAL_PIXEL_FORMAT_RAW10:
436 // Single plane 10bpp bayer data.
437 if (mBuffer->width % 4) {
438 ALOGE("Width is not multiple of 4 %d", mBuffer->width);
439 return AMEDIA_ERROR_UNKNOWN;
440 }
441 if (mBuffer->height % 2) {
442 ALOGE("Height is not multiple of 2 %d", mBuffer->height);
443 return AMEDIA_ERROR_UNKNOWN;
444 }
445 if (mBuffer->stride < (mBuffer->width * 10 / 8)) {
446 ALOGE("stride (%d) should be at least %d",
447 mBuffer->stride, mBuffer->width * 10 / 8);
448 return AMEDIA_ERROR_UNKNOWN;
449 }
450 pData = mBuffer->data;
451 dataSize = mBuffer->stride * mBuffer->height;
452 break;
453 case HAL_PIXEL_FORMAT_RAW12:
454 // Single plane 10bpp bayer data.
455 if (mBuffer->width % 4) {
456 ALOGE("Width is not multiple of 4 %d", mBuffer->width);
457 return AMEDIA_ERROR_UNKNOWN;
458 }
459 if (mBuffer->height % 2) {
460 ALOGE("Height is not multiple of 2 %d", mBuffer->height);
461 return AMEDIA_ERROR_UNKNOWN;
462 }
463 if (mBuffer->stride < (mBuffer->width * 12 / 8)) {
464 ALOGE("stride (%d) should be at least %d",
465 mBuffer->stride, mBuffer->width * 12 / 8);
466 return AMEDIA_ERROR_UNKNOWN;
467 }
468 pData = mBuffer->data;
469 dataSize = mBuffer->stride * mBuffer->height;
470 break;
471 case HAL_PIXEL_FORMAT_RGBA_8888:
472 case HAL_PIXEL_FORMAT_RGBX_8888:
473 // Single plane, 32bpp.
474 bytesPerPixel = 4;
475 pData = mBuffer->data;
476 dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
477 break;
478 case HAL_PIXEL_FORMAT_RGB_565:
479 // Single plane, 16bpp.
480 bytesPerPixel = 2;
481 pData = mBuffer->data;
482 dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
483 break;
484 case HAL_PIXEL_FORMAT_RGB_888:
485 // Single plane, 24bpp.
486 bytesPerPixel = 3;
487 pData = mBuffer->data;
488 dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
489 break;
490 default:
491 ALOGE("Pixel format: 0x%x is unsupported", fmt);
492 return AMEDIA_ERROR_UNSUPPORTED;
493 }
494
495 *data = pData;
496 *dataLength = dataSize;
497 return AMEDIA_OK;
498 }
499
500 EXPORT
AImage_delete(AImage * image)501 void AImage_delete(AImage* image) {
502 ALOGV("%s", __FUNCTION__);
503 if (image != nullptr) {
504 image->lockReader();
505 image->close();
506 image->unlockReader();
507 if (!image->isClosed()) {
508 LOG_ALWAYS_FATAL("Image close failed!");
509 }
510 image->free();
511 }
512 return;
513 }
514
515 EXPORT
AImage_getWidth(const AImage * image,int32_t * width)516 media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
517 ALOGV("%s", __FUNCTION__);
518 if (image == nullptr || width == nullptr) {
519 ALOGE("%s: bad argument. image %p width %p",
520 __FUNCTION__, image, width);
521 return AMEDIA_ERROR_INVALID_PARAMETER;
522 }
523 return image->getWidth(width);
524 }
525
526 EXPORT
AImage_getHeight(const AImage * image,int32_t * height)527 media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
528 ALOGV("%s", __FUNCTION__);
529 if (image == nullptr || height == nullptr) {
530 ALOGE("%s: bad argument. image %p height %p",
531 __FUNCTION__, image, height);
532 return AMEDIA_ERROR_INVALID_PARAMETER;
533 }
534 return image->getHeight(height);
535 }
536
537 EXPORT
AImage_getFormat(const AImage * image,int32_t * format)538 media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
539 ALOGV("%s", __FUNCTION__);
540 if (image == nullptr || format == nullptr) {
541 ALOGE("%s: bad argument. image %p format %p",
542 __FUNCTION__, image, format);
543 return AMEDIA_ERROR_INVALID_PARAMETER;
544 }
545 return image->getFormat(format);
546 }
547
548 EXPORT
AImage_getCropRect(const AImage * image,AImageCropRect * rect)549 media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
550 ALOGV("%s", __FUNCTION__);
551 if (image == nullptr || rect == nullptr) {
552 ALOGE("%s: bad argument. image %p rect %p",
553 __FUNCTION__, image, rect);
554 return AMEDIA_ERROR_INVALID_PARAMETER;
555 }
556 // For now AImage only supports camera outputs where cropRect is always full window
557 int32_t width = -1;
558 media_status_t ret = image->getWidth(&width);
559 if (ret != AMEDIA_OK) {
560 return ret;
561 }
562 int32_t height = -1;
563 ret = image->getHeight(&height);
564 if (ret != AMEDIA_OK) {
565 return ret;
566 }
567 rect->left = 0;
568 rect->top = 0;
569 rect->right = width;
570 rect->bottom = height;
571 return AMEDIA_OK;
572 }
573
574 EXPORT
AImage_getTimestamp(const AImage * image,int64_t * timestampNs)575 media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
576 ALOGV("%s", __FUNCTION__);
577 if (image == nullptr || timestampNs == nullptr) {
578 ALOGE("%s: bad argument. image %p timestampNs %p",
579 __FUNCTION__, image, timestampNs);
580 return AMEDIA_ERROR_INVALID_PARAMETER;
581 }
582 return image->getTimestamp(timestampNs);
583 }
584
585 EXPORT
AImage_getNumberOfPlanes(const AImage * image,int32_t * numPlanes)586 media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
587 ALOGV("%s", __FUNCTION__);
588 if (image == nullptr || numPlanes == nullptr) {
589 ALOGE("%s: bad argument. image %p numPlanes %p",
590 __FUNCTION__, image, numPlanes);
591 return AMEDIA_ERROR_INVALID_PARAMETER;
592 }
593 return image->getNumPlanes(numPlanes);
594 }
595
596 EXPORT
AImage_getPlanePixelStride(const AImage * image,int planeIdx,int32_t * pixelStride)597 media_status_t AImage_getPlanePixelStride(
598 const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
599 ALOGV("%s", __FUNCTION__);
600 if (image == nullptr || pixelStride == nullptr) {
601 ALOGE("%s: bad argument. image %p pixelStride %p",
602 __FUNCTION__, image, pixelStride);
603 return AMEDIA_ERROR_INVALID_PARAMETER;
604 }
605 return image->getPlanePixelStride(planeIdx, pixelStride);
606 }
607
608 EXPORT
AImage_getPlaneRowStride(const AImage * image,int planeIdx,int32_t * rowStride)609 media_status_t AImage_getPlaneRowStride(
610 const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
611 ALOGV("%s", __FUNCTION__);
612 if (image == nullptr || rowStride == nullptr) {
613 ALOGE("%s: bad argument. image %p rowStride %p",
614 __FUNCTION__, image, rowStride);
615 return AMEDIA_ERROR_INVALID_PARAMETER;
616 }
617 return image->getPlaneRowStride(planeIdx, rowStride);
618 }
619
620 EXPORT
AImage_getPlaneData(const AImage * image,int planeIdx,uint8_t ** data,int * dataLength)621 media_status_t AImage_getPlaneData(
622 const AImage* image, int planeIdx,
623 /*out*/uint8_t** data, /*out*/int* dataLength) {
624 ALOGV("%s", __FUNCTION__);
625 if (image == nullptr || data == nullptr || dataLength == nullptr) {
626 ALOGE("%s: bad argument. image %p data %p dataLength %p",
627 __FUNCTION__, image, data, dataLength);
628 return AMEDIA_ERROR_INVALID_PARAMETER;
629 }
630 return image->getPlaneData(planeIdx, data, dataLength);
631 }
632