am 8acfdc7b: Merge "camera2: Hide JPEGs in RGBA gralloc buffers." into lmp-dev

* commit '8acfdc7bf6b8ee5250351723ab2eef28f2b71e51':
  camera2: Hide JPEGs in RGBA gralloc buffers.
This commit is contained in:
Ruben Brunk
2014-09-24 23:01:08 +00:00
committed by Android Git Automerger
9 changed files with 181 additions and 108 deletions

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -42,71 +42,6 @@ public class RequestHolder {
private final int mNumPreviewTargets;
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.
*
@@ -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,16 +68,80 @@ 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}.

View File

@@ -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.");

View File

@@ -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 +

View File

@@ -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;