Gralloc/Camera3: Support new HAL_PIXEL_FORMAT_YCbCr_420_888 format
Enable flexible YUV format buffers from the camera.
- Add gralloc alloc support for YCbCr_420_888, mapped to NV21
- Add gralloc lock_ycbcr method
- Add new format to list supported by camera HAL
- Fix minor compilation warnings
Bug: 8734880
Change-Id: I68a8cc126985c7d5ae100a87b31c60ee59074cd3
diff --git a/camera/EmulatedFakeCamera3.cpp b/camera/EmulatedFakeCamera3.cpp
index b82c4c0..2513c19 100644
--- a/camera/EmulatedFakeCamera3.cpp
+++ b/camera/EmulatedFakeCamera3.cpp
@@ -51,12 +51,15 @@
const int64_t MSEC = USEC * 1000LL;
const int64_t SEC = MSEC * 1000LL;
-const uint32_t EmulatedFakeCamera3::kAvailableFormats[4] = {
+const int32_t EmulatedFakeCamera3::kAvailableFormats[5] = {
HAL_PIXEL_FORMAT_RAW_SENSOR,
HAL_PIXEL_FORMAT_BLOB,
HAL_PIXEL_FORMAT_RGBA_8888,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ // These are handled by YCbCr_420_888
// HAL_PIXEL_FORMAT_YV12,
- HAL_PIXEL_FORMAT_YCrCb_420_SP
+ // HAL_PIXEL_FORMAT_YCrCb_420_SP,
+ HAL_PIXEL_FORMAT_YCbCr_420_888
};
const uint32_t EmulatedFakeCamera3::kAvailableRawSizes[2] = {
@@ -294,6 +297,21 @@
}
inputStream = newStream;
}
+
+ bool validFormat = false;
+ for (size_t f = 0;
+ f < sizeof(kAvailableFormats)/sizeof(kAvailableFormats[0]);
+ f++) {
+ if (newStream->format == kAvailableFormats[f]) {
+ validFormat = true;
+ break;
+ }
+ }
+ if (!validFormat) {
+ ALOGE("%s: Unsupported stream format 0x%x requested",
+ __FUNCTION__, newStream->format);
+ return BAD_VALUE;
+ }
}
mInputStream = inputStream;
@@ -877,8 +895,26 @@
if (res == OK) {
// Lock buffer for writing
const Rect rect(destBuf.width, destBuf.height);
- res = GraphicBufferMapper::get().lock(*(destBuf.buffer),
- GRALLOC_USAGE_HW_CAMERA_WRITE, rect, (void**)&(destBuf.img));
+ if (srcBuf.stream->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ if (privBuffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+ android_ycbcr ycbcr = android_ycbcr();
+ res = GraphicBufferMapper::get().lockYCbCr(
+ *(destBuf.buffer),
+ GRALLOC_USAGE_HW_CAMERA_WRITE, rect,
+ &ycbcr);
+ // This is only valid because we know that emulator's
+ // YCbCr_420_888 is really contiguous NV21 under the hood
+ destBuf.img = static_cast<uint8_t*>(ycbcr.y);
+ } else {
+ ALOGE("Unexpected private format for flexible YUV: 0x%x",
+ privBuffer->format);
+ res = INVALID_OPERATION;
+ }
+ } else {
+ res = GraphicBufferMapper::get().lock(*(destBuf.buffer),
+ GRALLOC_USAGE_HW_CAMERA_WRITE, rect,
+ (void**)&(destBuf.img));
+ }
if (res != OK) {
ALOGE("%s: Request %d: Buffer %d: Unable to lock buffer",
__FUNCTION__, frameNumber, i);
@@ -886,7 +922,8 @@
}
if (res != OK) {
- // Either waiting or locking failed. Unlock locked buffers and bail out.
+ // Either waiting or locking failed. Unlock locked buffers and bail
+ // out.
for (size_t j = 0; j < i; j++) {
GraphicBufferMapper::get().unlock(
*(request->output_buffers[i].buffer));
@@ -1111,8 +1148,8 @@
// android.scaler
info.update(ANDROID_SCALER_AVAILABLE_FORMATS,
- (int32_t*)kAvailableFormats,
- sizeof(kAvailableFormats)/sizeof(uint32_t));
+ kAvailableFormats,
+ sizeof(kAvailableFormats)/sizeof(int32_t));
info.update(ANDROID_SCALER_AVAILABLE_RAW_SIZES,
(int32_t*)kAvailableRawSizes,
diff --git a/camera/EmulatedFakeCamera3.h b/camera/EmulatedFakeCamera3.h
index 0b3e2db..e9ef184 100644
--- a/camera/EmulatedFakeCamera3.h
+++ b/camera/EmulatedFakeCamera3.h
@@ -135,7 +135,7 @@
// sensor-generated buffers which use a nonpositive ID. Otherwise, HAL3 has
// no concept of a stream id.
static const uint32_t kGenericStreamId = 1;
- static const uint32_t kAvailableFormats[];
+ static const int32_t kAvailableFormats[];
static const uint32_t kAvailableRawSizes[];
static const uint64_t kAvailableRawMinDurations[];
static const uint32_t kAvailableProcessedSizesBack[];
diff --git a/opengl/system/OpenglSystemCommon/gralloc_cb.h b/opengl/system/OpenglSystemCommon/gralloc_cb.h
index a207401..fd35473 100644
--- a/opengl/system/OpenglSystemCommon/gralloc_cb.h
+++ b/opengl/system/OpenglSystemCommon/gralloc_cb.h
@@ -30,13 +30,14 @@
struct cb_handle_t : public native_handle {
cb_handle_t(int p_fd, int p_ashmemSize, int p_usage,
- int p_width, int p_height, int p_format,
- int p_glFormat, int p_glType) :
+ int p_width, int p_height, int p_frameworkFormat,
+ int p_format, int p_glFormat, int p_glType) :
fd(p_fd),
magic(BUFFER_HANDLE_MAGIC),
usage(p_usage),
width(p_width),
height(p_height),
+ frameworkFormat(p_frameworkFormat),
format(p_format),
glFormat(p_glFormat),
glType(p_glType),
@@ -89,6 +90,7 @@
int usage; // usage bits the buffer was created with
int width; // buffer width
int height; // buffer height
+ int frameworkFormat; // format requested by the Android framework
int format; // real internal pixel format format
int glFormat; // OpenGL format enum used for host h/w color buffer
int glType; // OpenGL type enum used when uploading to host
diff --git a/opengl/system/gralloc/gralloc.cpp b/opengl/system/gralloc/gralloc.cpp
index 311146f..ed5d05f 100644
--- a/opengl/system/gralloc/gralloc.cpp
+++ b/opengl/system/gralloc/gralloc.cpp
@@ -154,6 +154,8 @@
bool hw_cam_read = usage & GRALLOC_USAGE_HW_CAMERA_READ;
bool hw_vid_enc_read = usage & GRALLOC_USAGE_HW_VIDEO_ENCODER;
+ // Keep around original requested format for later validation
+ int frameworkFormat = format;
// Pick the right concrete pixel format given the endpoints as encoded in
// the usage bits. Every end-point pair needs explicit listing here.
if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
@@ -178,8 +180,17 @@
w, h, usage);
return -EINVAL;
}
+ } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ // Flexible framework-accessible YUV format; map to NV21 for now
+ if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+ format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ }
+ if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ ALOGE("gralloc_alloc: Requested YCbCr_420_888, but no known "
+ "specific format for this usage: %d x %d, usage %x",
+ w, h, usage);
+ }
}
-
bool yuv_format = false;
int ashmem_size = 0;
@@ -297,7 +308,8 @@
}
cb_handle_t *cb = new cb_handle_t(fd, ashmem_size, usage,
- w, h, format, glFormat, glType);
+ w, h, frameworkFormat, format,
+ glFormat, glType);
if (ashmem_size > 0) {
//
@@ -350,7 +362,11 @@
pthread_mutex_unlock(&grdev->lock);
*pHandle = cb;
- *pStride = stride;
+ if (frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ *pStride = 0;
+ } else {
+ *pStride = stride;
+ }
return 0;
}
@@ -580,7 +596,7 @@
ERR("gralloc_unregister_buffer(%p): unmap failed", cb);
return -EINVAL;
}
- cb->ashmemBase = NULL;
+ cb->ashmemBase = 0;
cb->mappedPid = 0;
}
@@ -605,6 +621,12 @@
return -EINVAL;
}
+ // validate format
+ if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ ALOGE("gralloc_lock can't be used with YCbCr_420_888 format");
+ return -EINVAL;
+ }
+
// Validate usage,
// 1. cannot be locked for hw access
// 2. lock for either sw read or write.
@@ -759,6 +781,109 @@
return 0;
}
+static int gralloc_lock_ycbcr(gralloc_module_t const* module,
+ buffer_handle_t handle, int usage,
+ int l, int t, int w, int h,
+ android_ycbcr *ycbcr)
+{
+ // Not supporting fallback module for YCbCr
+ if (sFallback != NULL) {
+ return -EINVAL;
+ }
+
+ if (!ycbcr) {
+ ALOGE("gralloc_lock_ycbcr got NULL ycbcr struct");
+ return -EINVAL;
+ }
+
+ private_module_t *gr = (private_module_t *)module;
+ cb_handle_t *cb = (cb_handle_t *)handle;
+ if (!gr || !cb_handle_t::validate(cb)) {
+ ALOGE("gralloc_lock_ycbcr bad handle\n");
+ return -EINVAL;
+ }
+
+ if (cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ ALOGE("gralloc_lock_ycbcr can only be used with "
+ "HAL_PIXEL_FORMAT_YCbCr_420_888, got %x instead",
+ cb->frameworkFormat);
+ return -EINVAL;
+ }
+
+ // Validate usage
+ // For now, only allow camera write, software read.
+ bool sw_read = (0 != (usage & GRALLOC_USAGE_SW_READ_MASK));
+ bool hw_cam_write = (usage & GRALLOC_USAGE_HW_CAMERA_WRITE);
+ bool sw_read_allowed = (0 != (cb->usage & GRALLOC_USAGE_SW_READ_MASK));
+
+ if ( (!hw_cam_write && !sw_read) ||
+ (sw_read && !sw_read_allowed) ) {
+ ALOGE("gralloc_lock_ycbcr usage mismatch usage:0x%x cb->usage:0x%x\n",
+ usage, cb->usage);
+ return -EINVAL;
+ }
+
+ // Make sure memory is mapped, get address
+ if (cb->ashmemBasePid != getpid() || !cb->ashmemBase) {
+ return -EACCES;
+ }
+
+ uint8_t *cpu_addr = NULL;
+
+ if (cb->canBePosted()) {
+ cpu_addr = (uint8_t *)(cb->ashmemBase + sizeof(int));
+ }
+ else {
+ cpu_addr = (uint8_t *)(cb->ashmemBase);
+ }
+
+ // Calculate offsets to underlying YUV data
+ size_t yStride;
+ size_t cStride;
+ size_t yOffset;
+ size_t uOffset;
+ size_t vOffset;
+ size_t cStep;
+ switch (cb->format) {
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ yStride = cb->width;
+ cStride = cb->width;
+ yOffset = 0;
+ vOffset = yStride * cb->height;
+ uOffset = vOffset + 1;
+ cStep = 2;
+ break;
+ default:
+ ALOGE("gralloc_lock_ycbcr unexpected internal format %x",
+ cb->format);
+ return -EINVAL;
+ }
+
+ ycbcr->y = cpu_addr + yOffset;
+ ycbcr->cb = cpu_addr + uOffset;
+ ycbcr->cr = cpu_addr + vOffset;
+ ycbcr->ystride = yStride;
+ ycbcr->cstride = cStride;
+ ycbcr->chroma_step = cStep;
+
+ // Zero out reserved fields
+ memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
+
+ //
+ // Keep locked region if locked for s/w write access.
+ //
+ cb->lockedLeft = l;
+ cb->lockedTop = t;
+ cb->lockedWidth = w;
+ cb->lockedHeight = h;
+
+ DD("gralloc_lock_ycbcr success. usage: %x, ycbcr.y: %p, .cb: %p, .cr: %p, "
+ ".ystride: %d , .cstride: %d, .chroma_step: %d", usage,
+ ycbcr->y, ycbcr->cb, ycbcr->cr, ycbcr->ystride, ycbcr->cstride,
+ ycbcr->chroma_step);
+
+ return 0;
+}
static int gralloc_device_open(const hw_module_t* module,
const char* name,
@@ -881,8 +1006,8 @@
base: {
common: {
tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
+ module_api_version: GRALLOC_MODULE_API_VERSION_0_2,
+ hal_api_version: 0,
id: GRALLOC_HARDWARE_MODULE_ID,
name: "Graphics Memory Allocator Module",
author: "The Android Open Source Project",
@@ -894,7 +1019,9 @@
unregisterBuffer: gralloc_unregister_buffer,
lock: gralloc_lock,
unlock: gralloc_unlock,
- perform: NULL
+ perform: NULL,
+ lock_ycbcr: gralloc_lock_ycbcr,
+ reserved_proc: {0, }
}
};