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 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 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 49 AImage::isClosed() const { 50 Mutex::Autolock _l(mLock); 51 return mIsClosed; 52 } 53 54 void 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 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 83 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 93 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 103 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 117 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 131 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 145 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 159 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 173 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 228 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 302 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 336 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 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 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 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 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 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 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 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 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 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 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