blob: 39b560b393a998b0ae80df180009ede9ef76c7d5 [file] [log] [blame]
James Dong79f407c2011-05-05 12:50:04 -07001/*
2 * Copyright 2011, 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// #define LOG_NDEBUG 0
18#define LOG_TAG "AndroidMediaUtils"
19
Colin Cross76de4f62017-05-15 18:10:40 -070020#include <hardware/camera3.h>
James Dong79f407c2011-05-05 12:50:04 -070021#include <utils/Log.h>
22#include "android_media_Utils.h"
23
Zhijun He0ab41622016-02-25 16:00:38 -080024#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
25
Shuzhen Wangf655b1c2018-12-28 15:40:36 -080026// Must be in sync with the value in HeicCompositeStream.cpp
27#define CAMERA3_HEIC_BLOB_ID 0x00FE
28
James Dong79f407c2011-05-05 12:50:04 -070029namespace android {
30
Zhijun He0ab41622016-02-25 16:00:38 -080031// -----------Utility functions used by ImageReader/Writer JNI-----------------
32
33enum {
34 IMAGE_MAX_NUM_PLANES = 3,
35};
36
37bool usingRGBAToJpegOverride(int32_t imageFormat,
38 int32_t containerFormat) {
39 return containerFormat == HAL_PIXEL_FORMAT_BLOB && imageFormat == HAL_PIXEL_FORMAT_RGBA_8888;
40}
41
42int32_t applyFormatOverrides(int32_t imageFormat, int32_t containerFormat) {
43 // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
44 // write limitations for some platforms (b/17379185).
45 if (usingRGBAToJpegOverride(imageFormat, containerFormat)) {
46 return HAL_PIXEL_FORMAT_BLOB;
47 }
48 return containerFormat;
49}
50
51bool isFormatOpaque(int format) {
52 // This is the only opaque format exposed in the ImageFormat public API.
53 // Note that we do support CPU access for HAL_PIXEL_FORMAT_RAW_OPAQUE
54 // (ImageFormat#RAW_PRIVATE) so it doesn't count as opaque here.
55 return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
56}
57
58bool isPossiblyYUV(PixelFormat format) {
59 switch (static_cast<int>(format)) {
60 case HAL_PIXEL_FORMAT_RGBA_8888:
61 case HAL_PIXEL_FORMAT_RGBX_8888:
62 case HAL_PIXEL_FORMAT_RGB_888:
63 case HAL_PIXEL_FORMAT_RGB_565:
64 case HAL_PIXEL_FORMAT_BGRA_8888:
65 case HAL_PIXEL_FORMAT_Y8:
66 case HAL_PIXEL_FORMAT_Y16:
67 case HAL_PIXEL_FORMAT_RAW16:
Emilian Peev62d40542021-11-04 15:22:02 -070068 case HAL_PIXEL_FORMAT_RAW12:
Zhijun He0ab41622016-02-25 16:00:38 -080069 case HAL_PIXEL_FORMAT_RAW10:
70 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
71 case HAL_PIXEL_FORMAT_BLOB:
72 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
Emilian Peevfd37b042021-01-21 11:38:34 -080073 case HAL_PIXEL_FORMAT_YCBCR_P010:
Zhijun He0ab41622016-02-25 16:00:38 -080074 return false;
75
76 case HAL_PIXEL_FORMAT_YV12:
77 case HAL_PIXEL_FORMAT_YCbCr_420_888:
78 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
79 default:
80 return true;
81 }
82}
83
Shuzhen Wangf655b1c2018-12-28 15:40:36 -080084uint32_t Image_getBlobSize(LockedImage* buffer, bool usingRGBAOverride) {
Zhijun He0ab41622016-02-25 16:00:38 -080085 ALOGV("%s", __FUNCTION__);
86 LOG_ALWAYS_FATAL_IF(buffer == NULL, "Input buffer is NULL!!!");
87 uint32_t size = 0;
88 uint32_t width = buffer->width;
Shuzhen Wangf655b1c2018-12-28 15:40:36 -080089 uint8_t* blobBuffer = buffer->data;
Zhijun He0ab41622016-02-25 16:00:38 -080090
91 if (usingRGBAOverride) {
92 width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
93 }
94
Shuzhen Wangf655b1c2018-12-28 15:40:36 -080095 // First check for BLOB transport header at the end of the buffer
96 uint8_t* header = blobBuffer + (width - sizeof(struct camera3_jpeg_blob));
Zhijun He0ab41622016-02-25 16:00:38 -080097 struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
Shuzhen Wangf655b1c2018-12-28 15:40:36 -080098 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID ||
99 blob->jpeg_blob_id == CAMERA3_HEIC_BLOB_ID) {
Zhijun He0ab41622016-02-25 16:00:38 -0800100 size = blob->jpeg_size;
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800101 ALOGV("%s: Jpeg/Heic size = %d", __FUNCTION__, size);
Zhijun He0ab41622016-02-25 16:00:38 -0800102 }
103
104 // failed to find size, default to whole buffer
105 if (size == 0) {
106 /*
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800107 * This is a problem because not including the JPEG/BLOB header
108 * means that in certain rare situations a regular JPEG/HEIC blob
Zhijun He0ab41622016-02-25 16:00:38 -0800109 * will be mis-identified as having a header, in which case
110 * we will get a garbage size value.
111 */
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800112 ALOGW("%s: No JPEG/HEIC header detected, defaulting to size=width=%d",
Zhijun He0ab41622016-02-25 16:00:38 -0800113 __FUNCTION__, width);
114 size = width;
115 }
116
117 return size;
118}
119
120status_t getLockedImageInfo(LockedImage* buffer, int idx,
121 int32_t containerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
122 ALOGV("%s", __FUNCTION__);
123 LOG_ALWAYS_FATAL_IF(buffer == NULL, "Input buffer is NULL!!!");
124 LOG_ALWAYS_FATAL_IF(base == NULL, "base is NULL!!!");
125 LOG_ALWAYS_FATAL_IF(size == NULL, "size is NULL!!!");
126 LOG_ALWAYS_FATAL_IF(pixelStride == NULL, "pixelStride is NULL!!!");
127 LOG_ALWAYS_FATAL_IF(rowStride == NULL, "rowStride is NULL!!!");
128 LOG_ALWAYS_FATAL_IF((idx >= IMAGE_MAX_NUM_PLANES) || (idx < 0), "idx (%d) is illegal", idx);
129
130 ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
131
132 uint32_t dataSize, ySize, cSize, cStride;
133 uint32_t pStride = 0, rStride = 0;
134 uint8_t *cb, *cr;
135 uint8_t *pData = NULL;
136 int bytesPerPixel = 0;
137
138 dataSize = ySize = cSize = cStride = 0;
139 int32_t fmt = buffer->flexFormat;
140
141 bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, containerFormat);
142 fmt = applyFormatOverrides(fmt, containerFormat);
143 switch (fmt) {
144 case HAL_PIXEL_FORMAT_YCbCr_420_888:
Clément Julliard2b644212020-09-09 14:15:29 +0000145 // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
146 if (buffer->width % 2 != 0) {
147 ALOGE("YCbCr_420_888: width (%d) should be a multiple of 2", buffer->width);
148 return BAD_VALUE;
149 }
150
151 if (buffer->height % 2 != 0) {
152 ALOGE("YCbCr_420_888: height (%d) should be a multiple of 2", buffer->height);
153 return BAD_VALUE;
154 }
155
156 if (buffer->width <= 0) {
157 ALOGE("YCbCr_420_888: width (%d) should be a > 0", buffer->width);
158 return BAD_VALUE;
159 }
160
161 if (buffer->height <= 0) {
162 ALOGE("YCbCr_420_888: height (%d) should be a > 0", buffer->height);
163 return BAD_VALUE;
164 }
165
Zhijun He0ab41622016-02-25 16:00:38 -0800166 pData =
167 (idx == 0) ?
168 buffer->data :
169 (idx == 1) ?
170 buffer->dataCb :
171 buffer->dataCr;
172 // only map until last pixel
173 if (idx == 0) {
174 pStride = 1;
175 rStride = buffer->stride;
176 dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
177 } else {
178 pStride = buffer->chromaStep;
179 rStride = buffer->chromaStride;
180 dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
181 buffer->chromaStep * (buffer->width / 2 - 1) + 1;
182 }
183 break;
184 // NV21
185 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Clément Julliard2b644212020-09-09 14:15:29 +0000186 // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
187 if (buffer->width % 2 != 0) {
188 ALOGE("YCrCb_420_SP: width (%d) should be a multiple of 2", buffer->width);
189 return BAD_VALUE;
190 }
191
192 if (buffer->height % 2 != 0) {
193 ALOGE("YCrCb_420_SP: height (%d) should be a multiple of 2", buffer->height);
194 return BAD_VALUE;
195 }
196
197 if (buffer->width <= 0) {
198 ALOGE("YCrCb_420_SP: width (%d) should be a > 0", buffer->width);
199 return BAD_VALUE;
200 }
201
202 if (buffer->height <= 0) {
203 ALOGE("YCrCb_420_SP: height (%d) should be a > 0", buffer->height);
204 return BAD_VALUE;
205 }
206
Zhijun He0ab41622016-02-25 16:00:38 -0800207 cr = buffer->data + (buffer->stride * buffer->height);
208 cb = cr + 1;
209 // only map until last pixel
210 ySize = buffer->width * (buffer->height - 1) + buffer->width;
211 cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
212
213 pData =
214 (idx == 0) ?
215 buffer->data :
216 (idx == 1) ?
217 cb:
218 cr;
219
220 dataSize = (idx == 0) ? ySize : cSize;
221 pStride = (idx == 0) ? 1 : 2;
222 rStride = buffer->width;
223 break;
224 case HAL_PIXEL_FORMAT_YV12:
Clément Julliard2b644212020-09-09 14:15:29 +0000225 // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
226 if (buffer->width % 2 != 0) {
227 ALOGE("YV12: width (%d) should be a multiple of 2", buffer->width);
228 return BAD_VALUE;
229 }
230
231 if (buffer->height % 2 != 0) {
232 ALOGE("YV12: height (%d) should be a multiple of 2", buffer->height);
233 return BAD_VALUE;
234 }
235
236 if (buffer->width <= 0) {
237 ALOGE("YV12: width (%d) should be a > 0", buffer->width);
238 return BAD_VALUE;
239 }
240
241 if (buffer->height <= 0) {
242 ALOGE("YV12: height (%d) should be a > 0", buffer->height);
243 return BAD_VALUE;
244 }
245
Zhijun He0ab41622016-02-25 16:00:38 -0800246 // Y and C stride need to be 16 pixel aligned.
247 LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
248 "Stride is not 16 pixel aligned %d", buffer->stride);
249
250 ySize = buffer->stride * buffer->height;
251 cStride = ALIGN(buffer->stride / 2, 16);
252 cr = buffer->data + ySize;
253 cSize = cStride * buffer->height / 2;
254 cb = cr + cSize;
255
256 pData =
257 (idx == 0) ?
258 buffer->data :
259 (idx == 1) ?
260 cb :
261 cr;
262 dataSize = (idx == 0) ? ySize : cSize;
263 pStride = 1;
264 rStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
265 break;
Emilian Peevfd37b042021-01-21 11:38:34 -0800266 case HAL_PIXEL_FORMAT_YCBCR_P010:
267 if (buffer->height % 2 != 0) {
268 ALOGE("YCBCR_P010: height (%d) should be a multiple of 2", buffer->height);
269 return BAD_VALUE;
270 }
271
272 if (buffer->width <= 0) {
273 ALOGE("YCBCR_P010: width (%d) should be a > 0", buffer->width);
274 return BAD_VALUE;
275 }
276
277 if (buffer->height <= 0) {
278 ALOGE("YCBCR_P010: height (%d) should be a > 0", buffer->height);
279 return BAD_VALUE;
280 }
281
282 ySize = (buffer->stride * 2) * buffer->height;
283 cSize = ySize / 2;
284 pStride = (idx == 0) ? 2 : 4;
285 cb = buffer->data + ySize;
286 cr = cb + 2;
287
288 pData = (idx == 0) ? buffer->data : (idx == 1) ? cb : cr;
289 dataSize = (idx == 0) ? ySize : cSize;
290 rStride = buffer->stride * 2;
291 break;
Zhijun He0ab41622016-02-25 16:00:38 -0800292 case HAL_PIXEL_FORMAT_Y8:
293 // Single plane, 8bpp.
294 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
295
296 pData = buffer->data;
297 dataSize = buffer->stride * buffer->height;
298 pStride = 1;
299 rStride = buffer->stride;
300 break;
301 case HAL_PIXEL_FORMAT_Y16:
302 bytesPerPixel = 2;
303 // Single plane, 16bpp, strides are specified in pixels, not in bytes
304 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
305
306 pData = buffer->data;
307 dataSize = buffer->stride * buffer->height * bytesPerPixel;
308 pStride = bytesPerPixel;
309 rStride = buffer->stride * 2;
310 break;
311 case HAL_PIXEL_FORMAT_BLOB:
312 // Used for JPEG data, height must be 1, width == size, single plane.
313 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
Yin-Chia Yeh7b790902016-03-14 16:17:38 -0700314 // When RGBA override is being used, buffer height will be equal to width
315 if (usingRGBAOverride) {
316 LOG_ALWAYS_FATAL_IF(buffer->height != buffer->width,
317 "RGBA override BLOB format buffer should have height == width");
318 } else {
319 LOG_ALWAYS_FATAL_IF(buffer->height != 1,
320 "BLOB format buffer should have height value 1");
321 }
322
Zhijun He0ab41622016-02-25 16:00:38 -0800323
324 pData = buffer->data;
Shuzhen Wangf655b1c2018-12-28 15:40:36 -0800325 dataSize = Image_getBlobSize(buffer, usingRGBAOverride);
Zhijun He0ab41622016-02-25 16:00:38 -0800326 pStride = 0;
327 rStride = 0;
328 break;
329 case HAL_PIXEL_FORMAT_RAW16:
330 // Single plane 16bpp bayer data.
331 bytesPerPixel = 2;
332 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
333 pData = buffer->data;
334 dataSize = buffer->stride * buffer->height * bytesPerPixel;
335 pStride = bytesPerPixel;
336 rStride = buffer->stride * 2;
337 break;
338 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
339 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
340 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
341 LOG_ALWAYS_FATAL_IF(buffer->height != 1,
342 "RAW_PRIVATE should has height value one but got %d", buffer->height);
343 pData = buffer->data;
344 dataSize = buffer->width;
345 pStride = 0; // RAW OPAQUE doesn't have pixel stride
346 rStride = 0; // RAW OPAQUE doesn't have row stride
347 break;
348 case HAL_PIXEL_FORMAT_RAW10:
349 // Single plane 10bpp bayer data.
350 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
351 LOG_ALWAYS_FATAL_IF(buffer->width % 4,
352 "Width is not multiple of 4 %d", buffer->width);
353 LOG_ALWAYS_FATAL_IF(buffer->height % 2,
354 "Height is not even %d", buffer->height);
355 LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
356 "stride (%d) should be at least %d",
357 buffer->stride, buffer->width * 10 / 8);
358 pData = buffer->data;
359 dataSize = buffer->stride * buffer->height;
360 pStride = 0;
361 rStride = buffer->stride;
362 break;
363 case HAL_PIXEL_FORMAT_RAW12:
364 // Single plane 10bpp bayer data.
365 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
366 LOG_ALWAYS_FATAL_IF(buffer->width % 4,
367 "Width is not multiple of 4 %d", buffer->width);
368 LOG_ALWAYS_FATAL_IF(buffer->height % 2,
369 "Height is not even %d", buffer->height);
370 LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 12 / 8),
371 "stride (%d) should be at least %d",
372 buffer->stride, buffer->width * 12 / 8);
373 pData = buffer->data;
374 dataSize = buffer->stride * buffer->height;
375 pStride = 0;
376 rStride = buffer->stride;
377 break;
378 case HAL_PIXEL_FORMAT_RGBA_8888:
379 case HAL_PIXEL_FORMAT_RGBX_8888:
380 // Single plane, 32bpp.
381 bytesPerPixel = 4;
382 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
383 pData = buffer->data;
384 dataSize = buffer->stride * buffer->height * bytesPerPixel;
385 pStride = bytesPerPixel;
386 rStride = buffer->stride * 4;
387 break;
388 case HAL_PIXEL_FORMAT_RGB_565:
389 // Single plane, 16bpp.
390 bytesPerPixel = 2;
391 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
392 pData = buffer->data;
393 dataSize = buffer->stride * buffer->height * bytesPerPixel;
394 pStride = bytesPerPixel;
395 rStride = buffer->stride * 2;
396 break;
397 case HAL_PIXEL_FORMAT_RGB_888:
398 // Single plane, 24bpp.
399 bytesPerPixel = 3;
400 LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
401 pData = buffer->data;
402 dataSize = buffer->stride * buffer->height * bytesPerPixel;
403 pStride = bytesPerPixel;
404 rStride = buffer->stride * 3;
405 break;
406 default:
407 return BAD_VALUE;
408 }
409
410 *base = pData;
411 *size = dataSize;
412 *pixelStride = pStride;
413 *rowStride = rStride;
414
415 return OK;
416}
417
418status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage,
419 const Rect& rect, int fenceFd, LockedImage* outputImage) {
420 ALOGV("%s: Try to lock the GraphicBuffer", __FUNCTION__);
421
422 if (buffer == nullptr || outputImage == nullptr) {
423 ALOGE("Input BufferItem or output LockedImage is NULL!");
424 return BAD_VALUE;
425 }
426 if (isFormatOpaque(buffer->getPixelFormat())) {
427 ALOGE("Opaque format buffer is not lockable!");
428 return BAD_VALUE;
429 }
430
431 void* pData = NULL;
432 android_ycbcr ycbcr = android_ycbcr();
433 status_t res;
434 int format = buffer->getPixelFormat();
435 int flexFormat = format;
436 if (isPossiblyYUV(format)) {
437 res = buffer->lockAsyncYCbCr(inUsage, rect, &ycbcr, fenceFd);
Clément Julliard2b644212020-09-09 14:15:29 +0000438
439 if (res != OK) {
440 ALOGW("lockAsyncYCbCr failed with error %d", res);
441 }
442
Zhijun He0ab41622016-02-25 16:00:38 -0800443 pData = ycbcr.y;
444 flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
445 }
446
447 // lockAsyncYCbCr for YUV is unsuccessful.
448 if (pData == NULL) {
449 res = buffer->lockAsync(inUsage, rect, &pData, fenceFd);
450 if (res != OK) {
451 ALOGE("Lock buffer failed!");
452 return res;
453 }
454 }
455
456 outputImage->data = reinterpret_cast<uint8_t*>(pData);
457 outputImage->width = buffer->getWidth();
458 outputImage->height = buffer->getHeight();
459 outputImage->format = format;
460 outputImage->flexFormat = flexFormat;
461 outputImage->stride =
462 (ycbcr.y != NULL) ? static_cast<uint32_t>(ycbcr.ystride) : buffer->getStride();
463
464 outputImage->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
465 outputImage->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
466 outputImage->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
467 outputImage->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
468 ALOGV("%s: Successfully locked the image from the GraphicBuffer", __FUNCTION__);
469 // Crop, transform, scalingMode, timestamp, and frameNumber should be set by caller,
470 // and cann't be set them here.
471 return OK;
472}
473
474status_t lockImageFromBuffer(BufferItem* bufferItem, uint32_t inUsage,
475 int fenceFd, LockedImage* outputImage) {
476 ALOGV("%s: Try to lock the BufferItem", __FUNCTION__);
477 if (bufferItem == nullptr || outputImage == nullptr) {
478 ALOGE("Input BufferItem or output LockedImage is NULL!");
479 return BAD_VALUE;
480 }
481
482 status_t res = lockImageFromBuffer(bufferItem->mGraphicBuffer, inUsage, bufferItem->mCrop,
483 fenceFd, outputImage);
484 if (res != OK) {
485 ALOGE("%s: lock graphic buffer failed", __FUNCTION__);
486 return res;
487 }
488
489 outputImage->crop = bufferItem->mCrop;
490 outputImage->transform = bufferItem->mTransform;
491 outputImage->scalingMode = bufferItem->mScalingMode;
492 outputImage->timestamp = bufferItem->mTimestamp;
493 outputImage->dataSpace = bufferItem->mDataSpace;
494 outputImage->frameNumber = bufferItem->mFrameNumber;
495 ALOGV("%s: Successfully locked the image from the BufferItem", __FUNCTION__);
496 return OK;
497}
498
499int getBufferWidth(BufferItem* buffer) {
500 if (buffer == NULL) return -1;
501
502 if (!buffer->mCrop.isEmpty()) {
503 return buffer->mCrop.getWidth();
504 }
505
506 ALOGV("%s: buffer->mGraphicBuffer: %p", __FUNCTION__, buffer->mGraphicBuffer.get());
507 return buffer->mGraphicBuffer->getWidth();
508}
509
510int getBufferHeight(BufferItem* buffer) {
511 if (buffer == NULL) return -1;
512
513 if (!buffer->mCrop.isEmpty()) {
514 return buffer->mCrop.getHeight();
515 }
516
517 ALOGV("%s: buffer->mGraphicBuffer: %p", __FUNCTION__, buffer->mGraphicBuffer.get());
518 return buffer->mGraphicBuffer->getHeight();
519}
520
James Dong79f407c2011-05-05 12:50:04 -0700521} // namespace android
522