diff options
| author | Ruben Brunk <rubenbrunk@google.com> | 2014-09-23 23:35:43 -0700 |
|---|---|---|
| committer | Ruben Brunk <rubenbrunk@google.com> | 2014-09-24 10:43:12 -0700 |
| commit | 0fd198ad89ec9c600bb1761b10d938146c28bb98 (patch) | |
| tree | 413982c700e2e5c76df3800ebdb8ec2ddc17a9bb | |
| parent | 54fee6862871170e2db0d02262a4724b7dad1485 (diff) | |
| download | frameworks_base-0fd198ad89ec9c600bb1761b10d938146c28bb98.zip frameworks_base-0fd198ad89ec9c600bb1761b10d938146c28bb98.tar.gz frameworks_base-0fd198ad89ec9c600bb1761b10d938146c28bb98.tar.bz2 | |
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
9 files changed, 181 insertions, 108 deletions
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.util.Log; import android.view.Surface; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -38,14 +39,16 @@ public class BurstHolder { * * @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 @@ public class LegacyCameraDevice implements AutoCloseable { 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 @@ public class RequestHolder { 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 @@ public class RequestHolder { 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 @@ public class RequestHolder { * @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 @@ public class RequestQueue { 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 class RequestQueue { 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 @@ public class RequestThreadManager { 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 @@ public class RequestThreadManager { 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 @@ public class RequestThreadManager { } 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 @@ public class RequestThreadManager { mGLThreadManager.ignoreNewFrames(); mGLThreadManager.waitUntilIdle(); } + resetJpegSurfaceFormats(mCallbackOutputs); mPreviewOutputs.clear(); mCallbackOutputs.clear(); mPreviewTexture = null; @@ -329,6 +339,12 @@ public class RequestThreadManager { 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 @@ public class RequestThreadManager { } 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 @@ public class RequestThreadManager { 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 @@ public class RequestThreadManager { 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 @@ public class SurfaceTextureRenderer { // 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 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, 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 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, } 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 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, // 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 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, 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 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, 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 @@ public class ImageReader implements AutoCloseable { 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 @@ public class ImageReader implements AutoCloseable { 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 @@ public class ImageReader implements AutoCloseable { 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 @@ static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer) 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 @@ static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* bu 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 @@ static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* bu *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 @@ static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* bu 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 @@ static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* bu 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 @@ static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buff 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 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, 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 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, 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 @@ static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz) 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 @@ static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx) 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 @@ static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx) 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 @@ static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx) 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 gImageReaderMethods[] = { }; 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 }, }; |
