camera2: Hide JPEGs in RGBA gralloc buffers.
Bug: 17379185
- WAR for SW Write usage flags being unavailable on
certain devices for JPEG (blob) format buffers.
Change-Id: Ic7299785b743f35dd47264b9d1cea01a88b71d91
diff --git a/core/java/android/hardware/camera2/legacy/BurstHolder.java b/core/java/android/hardware/camera2/legacy/BurstHolder.java
index c141c51..b9c89f8 100644
--- a/core/java/android/hardware/camera2/legacy/BurstHolder.java
+++ b/core/java/android/hardware/camera2/legacy/BurstHolder.java
@@ -22,6 +22,7 @@
import android.view.Surface;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -38,14 +39,16 @@
*
* @param requestId id of the burst request.
* @param repeating true if this burst is repeating.
- * @param requests a {@link java.util.List} of {@link CaptureRequest}s in this burst.
+ * @param requests a {@link List} of {@link CaptureRequest}s in this burst.
+ * @param jpegSurfaceIds a {@link Collection} of IDs for the surfaces that have jpeg outputs.
*/
- public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests) {
- mRequestBuilders = new ArrayList<RequestHolder.Builder>();
+ public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests,
+ Collection<Long> jpegSurfaceIds) {
+ mRequestBuilders = new ArrayList<>();
int i = 0;
for (CaptureRequest r : requests) {
mRequestBuilders.add(new RequestHolder.Builder(requestId, /*subsequenceId*/i,
- /*request*/r, repeating));
+ /*request*/r, repeating, jpegSurfaceIds));
++i;
}
mRepeating = repeating;
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index a724b41..4587c6f 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -522,7 +522,7 @@
return surfaceIds;
}
- static boolean containsSurfaceId(Surface s, List<Long> ids) {
+ static boolean containsSurfaceId(Surface s, Collection<Long> ids) {
long id = getSurfaceId(s);
return ids.contains(id);
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java
index 69c140b..edd8e4e 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHolder.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHolder.java
@@ -43,71 +43,6 @@
private volatile boolean mFailed = false;
/**
- * Returns true if the given surface requires jpeg buffers.
- *
- * @param s a {@link android.view.Surface} to check.
- * @return true if the surface requires a jpeg buffer.
- */
- public static boolean jpegType(Surface s)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- return LegacyCameraDevice.detectSurfaceType(s) ==
- CameraMetadataNative.NATIVE_JPEG_FORMAT;
- }
-
- /**
- * Returns true if the given surface requires non-jpeg buffer types.
- *
- * <p>
- * "Jpeg buffer" refers to the buffers returned in the jpeg
- * {@link android.hardware.Camera.PictureCallback}. Non-jpeg buffers are created using a tee
- * of the preview stream drawn to the surface
- * set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or
- * equivalent methods.
- * </p>
- * @param s a {@link android.view.Surface} to check.
- * @return true if the surface requires a non-jpeg buffer type.
- */
- public static boolean previewType(Surface s)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- return LegacyCameraDevice.detectSurfaceType(s) !=
- CameraMetadataNative.NATIVE_JPEG_FORMAT;
- }
-
- /**
- * Returns the number of surfaces targeted by the request that require jpeg buffers.
- */
- private static int numJpegTargets(CaptureRequest request) {
- int count = 0;
- for (Surface s : request.getTargets()) {
- try {
- if (jpegType(s)) {
- ++count;
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping...", e);
- }
- }
- return count;
- }
-
- /**
- * Returns the number of surfaces targeted by the request that require non-jpeg buffers.
- */
- private static int numPreviewTargets(CaptureRequest request) {
- int count = 0;
- for (Surface s : request.getTargets()) {
- try {
- if (previewType(s)) {
- ++count;
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping...", e);
- }
- }
- return count;
- }
-
- /**
* A builder class for {@link RequestHolder} objects.
*
* <p>
@@ -121,6 +56,7 @@
private final boolean mRepeating;
private final int mNumJpegTargets;
private final int mNumPreviewTargets;
+ private final Collection<Long> mJpegSurfaceIds;
/**
* Construct a new {@link Builder} to generate {@link RequestHolder} objects.
@@ -132,17 +68,81 @@
* @param repeating {@code true} if the request is repeating.
*/
public Builder(int requestId, int subsequenceId, CaptureRequest request,
- boolean repeating) {
+ boolean repeating, Collection<Long> jpegSurfaceIds) {
checkNotNull(request, "request must not be null");
mRequestId = requestId;
mSubsequenceId = subsequenceId;
mRequest = request;
mRepeating = repeating;
+ mJpegSurfaceIds = jpegSurfaceIds;
mNumJpegTargets = numJpegTargets(mRequest);
mNumPreviewTargets = numPreviewTargets(mRequest);
}
/**
+ * Returns true if the given surface requires jpeg buffers.
+ *
+ * @param s a {@link android.view.Surface} to check.
+ * @return true if the surface requires a jpeg buffer.
+ */
+ private boolean jpegType(Surface s)
+ throws LegacyExceptionUtils.BufferQueueAbandonedException {
+ return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
+ }
+
+ /**
+ * Returns true if the given surface requires non-jpeg buffer types.
+ *
+ * <p>
+ * "Jpeg buffer" refers to the buffers returned in the jpeg
+ * {@link android.hardware.Camera.PictureCallback}. Non-jpeg buffers are created using a tee
+ * of the preview stream drawn to the surface
+ * set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or
+ * equivalent methods.
+ * </p>
+ * @param s a {@link android.view.Surface} to check.
+ * @return true if the surface requires a non-jpeg buffer type.
+ */
+ private boolean previewType(Surface s)
+ throws LegacyExceptionUtils.BufferQueueAbandonedException {
+ return !jpegType(s);
+ }
+
+ /**
+ * Returns the number of surfaces targeted by the request that require jpeg buffers.
+ */
+ private int numJpegTargets(CaptureRequest request) {
+ int count = 0;
+ for (Surface s : request.getTargets()) {
+ try {
+ if (jpegType(s)) {
+ ++count;
+ }
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.d(TAG, "Surface abandoned, skipping...", e);
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Returns the number of surfaces targeted by the request that require non-jpeg buffers.
+ */
+ private int numPreviewTargets(CaptureRequest request) {
+ int count = 0;
+ for (Surface s : request.getTargets()) {
+ try {
+ if (previewType(s)) {
+ ++count;
+ }
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.d(TAG, "Surface abandoned, skipping...", e);
+ }
+ }
+ return count;
+ }
+
+ /**
* Build a new {@link RequestHolder} using with parameters generated from this
* {@link Builder}.
*
diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java
index 7598f99..c995029 100644
--- a/core/java/android/hardware/camera2/legacy/RequestQueue.java
+++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java
@@ -39,8 +39,11 @@
private long mCurrentFrameNumber = 0;
private long mCurrentRepeatingFrameNumber = INVALID_FRAME;
private int mCurrentRequestId = 0;
+ private final List<Long> mJpegSurfaceIds;
- public RequestQueue() {}
+ public RequestQueue(List<Long> jpegSurfaceIds) {
+ mJpegSurfaceIds = jpegSurfaceIds;
+ }
/**
* Return and remove the next burst on the queue.
@@ -117,7 +120,7 @@
public synchronized int submit(List<CaptureRequest> requests, boolean repeating,
/*out*/LongParcelable frameNumber) {
int requestId = mCurrentRequestId++;
- BurstHolder burst = new BurstHolder(requestId, repeating, requests);
+ BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
long ret = INVALID_FRAME;
if (burst.isRepeating()) {
Log.i(TAG, "Repeating capture request set.");
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 788b6d8..73edaee 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -91,9 +91,11 @@
private SurfaceTexture mPreviewTexture;
private Camera.Parameters mParams;
+ private final List<Long> mJpegSurfaceIds = new ArrayList<>();
+
private Size mIntermediateBufferSize;
- private final RequestQueue mRequestQueue = new RequestQueue();
+ private final RequestQueue mRequestQueue = new RequestQueue(mJpegSurfaceIds);
private LegacyRequest mLastRequest = null;
private SurfaceTexture mDummyTexture;
private Surface mDummySurface;
@@ -102,6 +104,10 @@
private final FpsCounter mPrevCounter = new FpsCounter("Incoming Preview");
private final FpsCounter mRequestCounter = new FpsCounter("Incoming Requests");
+ // Stuff JPEGs into HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers to get around SW write
+ // limitations for (b/17379185).
+ private static final boolean USE_BLOB_FORMAT_OVERRIDE = true;
+
/**
* Container object for Configure messages.
*/
@@ -197,10 +203,13 @@
}
for (Surface s : holder.getHolderTargets()) {
try {
- if (RequestHolder.jpegType(s)) {
+ if (LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds)) {
Log.i(TAG, "Producing jpeg buffer...");
- LegacyCameraDevice.setSurfaceDimens(s, data.length +
- LegacyCameraDevice.nativeGetJpegFooterSize(), /*height*/1);
+
+ int totalSize = data.length + LegacyCameraDevice.nativeGetJpegFooterSize();
+ totalSize += ((totalSize - 1) & ~0x3) + 4; // align to next octonibble
+
+ LegacyCameraDevice.setSurfaceDimens(s, totalSize, /*height*/1);
LegacyCameraDevice.setNextTimestamp(s, timestamp);
LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1,
CameraMetadataNative.NATIVE_JPEG_FORMAT);
@@ -316,6 +325,7 @@
mGLThreadManager.ignoreNewFrames();
mGLThreadManager.waitUntilIdle();
}
+ resetJpegSurfaceFormats(mCallbackOutputs);
mPreviewOutputs.clear();
mCallbackOutputs.clear();
mPreviewTexture = null;
@@ -329,6 +339,12 @@
LegacyCameraDevice.setSurfaceOrientation(s, facing, orientation);
switch (format) {
case CameraMetadataNative.NATIVE_JPEG_FORMAT:
+ if (USE_BLOB_FORMAT_OVERRIDE) {
+ // Override to RGBA_8888 format.
+ LegacyCameraDevice.setSurfaceFormat(s,
+ LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888);
+ }
+ mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s));
mCallbackOutputs.add(s);
break;
default:
@@ -426,8 +442,19 @@
}
mCamera.setParameters(mParams);
- // TODO: configure the JPEG surface with some arbitrary size
- // using LegacyCameraDevice.nativeConfigureSurface
+ }
+
+ private void resetJpegSurfaceFormats(Collection<Surface> surfaces) {
+ if (!USE_BLOB_FORMAT_OVERRIDE || surfaces == null) {
+ return;
+ }
+ for(Surface s : surfaces) {
+ try {
+ LegacyCameraDevice.setSurfaceFormat(s, LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB);
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.w(TAG, "Surface abandoned, skipping...", e);
+ }
+ }
}
/**
@@ -459,9 +486,8 @@
List<Size> configuredJpegSizes = new ArrayList<Size>();
for (Surface callbackSurface : callbackOutputs) {
try {
- int format = LegacyCameraDevice.detectSurfaceType(callbackSurface);
- if (format != CameraMetadataNative.NATIVE_JPEG_FORMAT) {
+ if (!LegacyCameraDevice.containsSurfaceId(callbackSurface, mJpegSurfaceIds)) {
continue; // Ignore non-JPEG callback formats
}
@@ -821,6 +847,7 @@
if (mCamera != null) {
mCamera.release();
}
+ resetJpegSurfaceFormats(mCallbackOutputs);
break;
default:
throw new AssertionError("Unhandled message " + msg.what +
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index c018c3e..c0d1d5e 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -581,6 +581,7 @@
// If pixel conversions aren't handled by egl, use a pbuffer
try {
if (LegacyCameraDevice.needsConversion(s)) {
+ // Always override to YV12 output for YUV surface formats.
LegacyCameraDevice.setSurfaceFormat(s, ImageFormat.YV12);
EGLSurfaceHolder holder = new EGLSurfaceHolder();
holder.surface = s;
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 980ead0..ee00161 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -200,7 +200,7 @@
switch(pixelFmt) {
case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
if (bufSize < width * height * 4) {
- ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions",
+ ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
__FUNCTION__, bufSize);
return BAD_VALUE;
}
@@ -222,7 +222,7 @@
}
case HAL_PIXEL_FORMAT_YV12: {
if (bufSize < width * height * 4) {
- ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions",
+ ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
__FUNCTION__, bufSize);
return BAD_VALUE;
}
@@ -259,7 +259,7 @@
// Software writes with YCbCr_420_888 format are unsupported
// by the gralloc module for now
if (bufSize < width * height * 4) {
- ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions",
+ ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
__FUNCTION__, bufSize);
return BAD_VALUE;
}
@@ -281,6 +281,18 @@
return BAD_VALUE;
}
int8_t* img = NULL;
+ struct camera3_jpeg_blob footer = {
+ jpeg_blob_id: CAMERA3_JPEG_BLOB_ID,
+ jpeg_size: (uint32_t)width
+ };
+
+ size_t totalSize = static_cast<size_t>(width) + sizeof(footer);
+ size_t padding = ((totalSize - 1) & ~0x3) + 4; // align to next octonibble
+ totalSize += padding;
+ if (anb->width != totalSize) {
+ ALOGE("%s: gralloc buffer wrong size to hold jpeg, failed to produce buffer.");
+ return BAD_VALUE;
+ }
ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
@@ -289,12 +301,9 @@
err);
return err;
}
- struct camera3_jpeg_blob footer = {
- jpeg_blob_id: CAMERA3_JPEG_BLOB_ID,
- jpeg_size: (uint32_t)width
- };
memcpy(img, pixelBuffer, width);
- memcpy(img + anb->width - sizeof(footer), &footer, sizeof(footer));
+ memset(img + width, 0, padding);
+ memcpy(img + totalSize - sizeof(footer), &footer, sizeof(footer));
break;
}
default: {
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index b786f94..b541454 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -642,7 +642,7 @@
private void createSurfacePlanes() {
mPlanes = new SurfacePlane[ImageReader.this.mNumPlanes];
for (int i = 0; i < ImageReader.this.mNumPlanes; i++) {
- mPlanes[i] = nativeCreatePlane(i);
+ mPlanes[i] = nativeCreatePlane(i, ImageReader.this.mFormat);
}
}
private class SurfacePlane extends android.media.Image.Plane {
@@ -661,7 +661,8 @@
if (mBuffer != null) {
return mBuffer;
} else {
- mBuffer = SurfaceImage.this.nativeImageGetBuffer(mIndex);
+ mBuffer = SurfaceImage.this.nativeImageGetBuffer(mIndex,
+ ImageReader.this.mFormat);
// Set the byteBuffer order according to host endianness (native order),
// otherwise, the byteBuffer order defaults to ByteOrder.BIG_ENDIAN.
return mBuffer.order(ByteOrder.nativeOrder());
@@ -711,8 +712,8 @@
private SurfacePlane[] mPlanes;
private boolean mIsImageValid;
- private synchronized native ByteBuffer nativeImageGetBuffer(int idx);
- private synchronized native SurfacePlane nativeCreatePlane(int idx);
+ private synchronized native ByteBuffer nativeImageGetBuffer(int idx, int readerFormat);
+ private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat);
}
private synchronized native void nativeInit(Object weakSelf, int w, int h,
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index fa4439d..a734774 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -317,8 +317,18 @@
return size;
}
+static int32_t applyFormatOverrides(int32_t bufferFormat, int32_t readerCtxFormat)
+{
+ // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
+ // write limitations for some platforms (b/17379185).
+ if (readerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888) {
+ return HAL_PIXEL_FORMAT_BLOB;
+ }
+ return bufferFormat;
+}
+
static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
- uint8_t **base, uint32_t *size)
+ uint8_t **base, uint32_t *size, int32_t readerFormat)
{
ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
ALOG_ASSERT(base != NULL, "base is NULL!!!");
@@ -334,6 +344,8 @@
dataSize = ySize = cSize = cStride = 0;
int32_t fmt = buffer->format;
+
+ fmt = applyFormatOverrides(fmt, readerFormat);
switch (fmt) {
case HAL_PIXEL_FORMAT_YCbCr_420_888:
pData =
@@ -458,7 +470,8 @@
*size = dataSize;
}
-static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx)
+static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
+ int32_t readerFormat)
{
ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx);
@@ -467,6 +480,9 @@
ALOG_ASSERT(buffer != NULL, "buffer is NULL");
int32_t fmt = buffer->format;
+
+ fmt = applyFormatOverrides(fmt, readerFormat);
+
switch (fmt) {
case HAL_PIXEL_FORMAT_YCbCr_420_888:
pixelStride = (idx == 0) ? 1 : buffer->chromaStep;
@@ -515,7 +531,8 @@
return pixelStride;
}
-static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx)
+static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
+ int32_t readerFormat)
{
ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
@@ -525,6 +542,8 @@
int32_t fmt = buffer->format;
+ fmt = applyFormatOverrides(fmt, readerFormat);
+
switch (fmt) {
case HAL_PIXEL_FORMAT_YCbCr_420_888:
rowStride = (idx == 0) ? buffer->stride : buffer->chromaStride;
@@ -777,9 +796,10 @@
outputHeight = buffer->crop.getHeight();
}
+ int imgReaderFmt = ctx->getBufferFormat();
int imageReaderWidth = ctx->getBufferWidth();
int imageReaderHeight = ctx->getBufferHeight();
- if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) &&
+ if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
(imageReaderWidth != outputWidth || imageReaderHeight > outputHeight)) {
/**
* For video decoder, the buffer height is actually the vertical stride,
@@ -795,15 +815,19 @@
return -1;
}
- int imgReaderFmt = ctx->getBufferFormat();
int bufFmt = buffer->format;
if (imgReaderFmt != bufFmt) {
- // Special casing for when producer switches to a format compatible with flexible YUV
- // (HAL_PIXEL_FORMAT_YCbCr_420_888).
+
if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
+ // Special casing for when producer switches to a format compatible with flexible YUV
+ // (HAL_PIXEL_FORMAT_YCbCr_420_888).
ctx->setBufferFormat(bufFmt);
- ALOGV("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
+ ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
+ } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB && bufFmt == HAL_PIXEL_FORMAT_RGBA_8888) {
+ // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
+ // write limitations for (b/17379185).
+ ALOGD("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__);
} else {
// Return the buffer to the queue.
consumer->unlockBuffer(*buffer);
@@ -843,7 +867,7 @@
return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
}
-static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx)
+static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx, int readerFormat)
{
int rowStride, pixelStride;
ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
@@ -854,8 +878,11 @@
if (buffer == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
}
- rowStride = Image_imageGetRowStride(env, buffer, idx);
- pixelStride = Image_imageGetPixelStride(env, buffer, idx);
+
+ readerFormat = Image_getPixelFormat(env, readerFormat);
+
+ rowStride = Image_imageGetRowStride(env, buffer, idx, readerFormat);
+ pixelStride = Image_imageGetPixelStride(env, buffer, idx, readerFormat);
jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
@@ -863,7 +890,7 @@
return surfPlaneObj;
}
-static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx)
+static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx, int readerFormat)
{
uint8_t *base = NULL;
uint32_t size = 0;
@@ -877,8 +904,10 @@
jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
}
+ readerFormat = Image_getPixelFormat(env, readerFormat);
+
// Create byteBuffer from native buffer
- Image_getLockedBufferInfo(env, buffer, idx, &base, &size);
+ Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerFormat);
if (size > static_cast<uint32_t>(INT32_MAX)) {
// Byte buffer have 'int capacity', so check the range
@@ -910,8 +939,8 @@
};
static JNINativeMethod gImageMethods[] = {
- {"nativeImageGetBuffer", "(I)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer },
- {"nativeCreatePlane", "(I)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
+ {"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer },
+ {"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
(void*)Image_createSurfacePlane },
};