Merge "Camera: Don't switch image callbacks during extension sessions" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-03-09 21:16:39 +00:00
committed by Android (Google) Code Review
2 changed files with 196 additions and 107 deletions

View File

@@ -61,6 +61,7 @@ import android.util.Pair;
import android.util.Size; import android.util.Size;
import android.view.Surface; import android.view.Surface;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -90,6 +91,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
private ImageReader mBurstCaptureImageReader = null; private ImageReader mBurstCaptureImageReader = null;
private ImageReader mStubCaptureImageReader = null; private ImageReader mStubCaptureImageReader = null;
private ImageWriter mRepeatingRequestImageWriter = null; private ImageWriter mRepeatingRequestImageWriter = null;
private CameraOutputImageCallback mRepeatingRequestImageCallback = null;
private CameraOutputImageCallback mBurstCaptureImageCallback = null;
private CameraExtensionJpegProcessor mImageJpegProcessor = null; private CameraExtensionJpegProcessor mImageJpegProcessor = null;
private ICaptureProcessorImpl mImageProcessor = null; private ICaptureProcessorImpl mImageProcessor = null;
@@ -400,8 +403,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
PREVIEW_QUEUE_SIZE, repeatingSurfaceInfo.mUsage); PREVIEW_QUEUE_SIZE, repeatingSurfaceInfo.mUsage);
mCameraRepeatingSurface = mRepeatingRequestImageReader.getSurface(); mCameraRepeatingSurface = mRepeatingRequestImageReader.getSurface();
} }
mRepeatingRequestImageCallback = new CameraOutputImageCallback(
mRepeatingRequestImageReader);
mRepeatingRequestImageReader mRepeatingRequestImageReader
.setOnImageAvailableListener(new ImageLoopbackCallback(), mHandler); .setOnImageAvailableListener(mRepeatingRequestImageCallback, mHandler);
} }
private void initializeBurstCapturePipeline() throws RemoteException { private void initializeBurstCapturePipeline() throws RemoteException {
@@ -440,6 +445,9 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT); CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT);
} }
mBurstCaptureImageCallback = new CameraOutputImageCallback(mBurstCaptureImageReader);
mBurstCaptureImageReader.setOnImageAvailableListener(mBurstCaptureImageCallback,
mHandler);
mCameraBurstSurface = mBurstCaptureImageReader.getSurface(); mCameraBurstSurface = mBurstCaptureImageReader.getSurface();
android.hardware.camera2.extension.Size sz = android.hardware.camera2.extension.Size sz =
new android.hardware.camera2.extension.Size(); new android.hardware.camera2.extension.Size();
@@ -534,7 +542,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mInternalRepeatingRequestEnabled = false; mInternalRepeatingRequestEnabled = false;
try { try {
return setRepeatingRequest(mPreviewExtender.getCaptureStage(), return setRepeatingRequest(mPreviewExtender.getCaptureStage(),
new RepeatingRequestHandler(request, executor, listener)); new RepeatingRequestHandler(request, executor, listener,
mRepeatingRequestImageCallback));
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(TAG, "Failed to set repeating request! Extension service does not " Log.e(TAG, "Failed to set repeating request! Extension service does not "
+ "respond"); + "respond");
@@ -648,7 +657,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} }
return mCaptureSession.captureBurstRequests(burstRequest, new HandlerExecutor(mHandler), return mCaptureSession.captureBurstRequests(burstRequest, new HandlerExecutor(mHandler),
new BurstRequestHandler(request, executor, listener, requestMap)); new BurstRequestHandler(request, executor, listener, requestMap,
mBurstCaptureImageCallback));
} }
@Override @Override
@@ -689,7 +699,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
if (!captureStageList.isEmpty()) { if (!captureStageList.isEmpty()) {
CaptureRequest disableRequest = createRequest(mCameraDevice, captureStageList, CaptureRequest disableRequest = createRequest(mCameraDevice, captureStageList,
mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW); mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW);
mCaptureSession.capture(disableRequest, new CloseRequestHandler(), mHandler); mCaptureSession.capture(disableRequest,
new CloseRequestHandler(mRepeatingRequestImageCallback), mHandler);
} }
mCaptureSession.close(); mCaptureSession.close();
@@ -735,11 +746,21 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
CameraExtensionCharacteristics.unregisterClient(mExtensionClientId); CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
} }
if (mRepeatingRequestImageCallback != null) {
mRepeatingRequestImageCallback.close();
mRepeatingRequestImageCallback = null;
}
if (mRepeatingRequestImageReader != null) { if (mRepeatingRequestImageReader != null) {
mRepeatingRequestImageReader.close(); mRepeatingRequestImageReader.close();
mRepeatingRequestImageReader = null; mRepeatingRequestImageReader = null;
} }
if (mBurstCaptureImageCallback != null) {
mBurstCaptureImageCallback.close();
mBurstCaptureImageCallback = null;
}
if (mBurstCaptureImageReader != null) { if (mBurstCaptureImageReader != null) {
mBurstCaptureImageReader.close(); mBurstCaptureImageReader.close();
mBurstCaptureImageReader = null; mBurstCaptureImageReader = null;
@@ -835,7 +856,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
ArrayList<CaptureStageImpl> initialRequestList = compileInitialRequestList(); ArrayList<CaptureStageImpl> initialRequestList = compileInitialRequestList();
if (!initialRequestList.isEmpty()) { if (!initialRequestList.isEmpty()) {
try { try {
setInitialCaptureRequest(initialRequestList, new InitialRequestHandler()); setInitialCaptureRequest(initialRequestList,
new InitialRequestHandler(mRepeatingRequestImageCallback));
} catch (CameraAccessException e) { } catch (CameraAccessException e) {
Log.e(TAG, "Failed to initialize the initial capture request!"); Log.e(TAG, "Failed to initialize the initial capture request!");
status = false; status = false;
@@ -843,7 +865,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} else { } else {
try { try {
setRepeatingRequest(mPreviewExtender.getCaptureStage(), setRepeatingRequest(mPreviewExtender.getCaptureStage(),
new RepeatingRequestHandler(null, null, null)); new RepeatingRequestHandler(null, null, null,
mRepeatingRequestImageCallback));
} catch (CameraAccessException | RemoteException e) { } catch (CameraAccessException | RemoteException e) {
Log.e(TAG, "Failed to initialize internal repeating request!"); Log.e(TAG, "Failed to initialize internal repeating request!");
status = false; status = false;
@@ -863,6 +886,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
private final ExtensionCaptureCallback mCallbacks; private final ExtensionCaptureCallback mCallbacks;
private final CaptureRequest mClientRequest; private final CaptureRequest mClientRequest;
private final HashMap<CaptureRequest, Integer> mCaptureRequestMap; private final HashMap<CaptureRequest, Integer> mCaptureRequestMap;
private final CameraOutputImageCallback mBurstImageCallback;
private HashMap<Integer, Pair<Image, TotalCaptureResult>> mCaptureStageMap = private HashMap<Integer, Pair<Image, TotalCaptureResult>> mCaptureStageMap =
new HashMap<>(); new HashMap<>();
@@ -874,11 +898,13 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
public BurstRequestHandler(@NonNull CaptureRequest request, @NonNull Executor executor, public BurstRequestHandler(@NonNull CaptureRequest request, @NonNull Executor executor,
@NonNull ExtensionCaptureCallback callbacks, @NonNull ExtensionCaptureCallback callbacks,
@NonNull HashMap<CaptureRequest, Integer> requestMap) { @NonNull HashMap<CaptureRequest, Integer> requestMap,
@Nullable CameraOutputImageCallback imageCallback) {
mClientRequest = request; mClientRequest = request;
mExecutor = executor; mExecutor = executor;
mCallbacks = callbacks; mCallbacks = callbacks;
mCaptureRequestMap = requestMap; mCaptureRequestMap = requestMap;
mBurstImageCallback = imageCallback;
} }
private void notifyCaptureFailed() { private void notifyCaptureFailed() {
@@ -893,6 +919,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
for (Pair<Image, TotalCaptureResult> captureStage : mCaptureStageMap.values()) {
captureStage.first.close();
}
mCaptureStageMap.clear();
} }
} }
@@ -905,8 +936,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
boolean initialCallback = false; boolean initialCallback = false;
synchronized (mInterfaceLock) { synchronized (mInterfaceLock) {
if ((mImageProcessor != null) && (mImageCallback == null)) { if ((mImageProcessor != null) && (mImageCallback == null)) {
mImageCallback = new ImageCallback(mBurstCaptureImageReader); mImageCallback = new ImageCallback();
mBurstCaptureImageReader.setOnImageAvailableListener(mImageCallback, mHandler);
initialCallback = true; initialCallback = true;
} else if (mImageProcessor == null) { } else if (mImageProcessor == null) {
// No burst expected in this case // No burst expected in this case
@@ -924,6 +954,10 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
} }
if ((mBurstImageCallback != null) && (mImageCallback != null)) {
mBurstImageCallback.registerListener(timestamp, mImageCallback);
}
} }
@Override @Override
@@ -1062,18 +1096,13 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} }
} }
private class ImageCallback implements ImageReader.OnImageAvailableListener { private class ImageCallback implements OnImageAvailableListener {
public ImageCallback(@NonNull ImageReader reader) { @Override
//Check for any pending buffers public void onImageAvailable(ImageReader reader, Image img) {
onImageAvailable(reader); if (mCaptureFailed) {
img.close();
} }
@Override
public void onImageAvailable(ImageReader reader) {
Image img;
try {
while ((!mCaptureRequestMap.isEmpty()) &&
(img = reader.acquireNextImage()) != null) {
long timestamp = img.getTimestamp(); long timestamp = img.getTimestamp();
reader.detachImage(img); reader.detachImage(img);
if (mCapturePendingMap.indexOfKey(timestamp) >= 0) { if (mCapturePendingMap.indexOfKey(timestamp) >= 0) {
@@ -1097,32 +1126,29 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
-1)); -1));
} }
} }
} catch (IllegalStateException e) {
// This is possible in case the maximum number of images is acquired.
}
}
} }
} }
private class ImageLoopbackCallback implements ImageReader.OnImageAvailableListener { private class ImageLoopbackCallback implements OnImageAvailableListener {
@Override public void onImageAvailable(ImageReader reader) { @Override
Image img; public void onImageAvailable(ImageReader reader, Image img) {
try {
img = reader.acquireNextImage();
} catch (IllegalStateException e) {
Log.e(TAG, "Failed to acquire and loopback image!");
return;
}
if (img == null) {
Log.e(TAG,
"Invalid image!");
return;
}
img.close(); img.close();
} }
} }
private class InitialRequestHandler extends CameraCaptureSession.CaptureCallback { private class InitialRequestHandler extends CameraCaptureSession.CaptureCallback {
private final CameraOutputImageCallback mImageCallback;
public InitialRequestHandler(CameraOutputImageCallback imageCallback) {
mImageCallback = imageCallback;
}
@Override
public void onCaptureStarted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, long timestamp, long frameNumber) {
mImageCallback.registerListener(timestamp, new ImageLoopbackCallback());
}
@Override @Override
public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session, public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session,
int sequenceId) { int sequenceId) {
@@ -1150,7 +1176,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
*/ */
try { try {
setRepeatingRequest(mPreviewExtender.getCaptureStage(), setRepeatingRequest(mPreviewExtender.getCaptureStage(),
new RepeatingRequestHandler(null, null, null)); new RepeatingRequestHandler(null, null, null,
mImageCallback));
} catch (CameraAccessException | RemoteException e) { } catch (CameraAccessException | RemoteException e) {
Log.e(TAG, "Failed to start the internal repeating request!"); Log.e(TAG, "Failed to start the internal repeating request!");
status = false; status = false;
@@ -1164,16 +1191,92 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} }
} }
private interface OnImageAvailableListener {
public void onImageAvailable (ImageReader reader, Image img);
}
private class CameraOutputImageCallback implements ImageReader.OnImageAvailableListener,
Closeable {
private final ImageReader mImageReader;
// Map timestamp to specific images and listeners
private HashMap<Long, Pair<Image, OnImageAvailableListener>> mImageListenerMap =
new HashMap<>();
private boolean mOutOfBuffers = false;
CameraOutputImageCallback(ImageReader imageReader) {
mImageReader = imageReader;
}
@Override
public void onImageAvailable(ImageReader reader) {
Image img;
try {
img = reader.acquireNextImage();
} catch (IllegalStateException e) {
Log.e(TAG, "Failed to acquire image, too many images pending!");
mOutOfBuffers = true;
return;
}
if (img == null) {
Log.e(TAG, "Invalid image!");
return;
}
Long timestamp = img.getTimestamp();
if (mImageListenerMap.containsKey(timestamp)) {
Pair<Image, OnImageAvailableListener> entry = mImageListenerMap.remove(timestamp);
if (entry.second != null) {
entry.second.onImageAvailable(reader, img);
} else {
Log.w(TAG, "Invalid image listener, dropping frame!");
img.close();
}
} else {
mImageListenerMap.put(img.getTimestamp(), new Pair<>(img, null));
}
}
public void registerListener(Long timestamp, OnImageAvailableListener listener) {
if (mImageListenerMap.containsKey(timestamp)) {
Pair<Image, OnImageAvailableListener> entry = mImageListenerMap.remove(timestamp);
if (entry.first != null) {
listener.onImageAvailable(mImageReader, entry.first);
if (mOutOfBuffers) {
mOutOfBuffers = false;
Log.w(TAG,"Out of buffers, retry!");
onImageAvailable(mImageReader);
}
} else {
Log.w(TAG, "No valid image for listener with ts: " +
timestamp.longValue());
}
} else {
mImageListenerMap.put(timestamp, new Pair<>(null, listener));
}
}
@Override
public void close() {
for (Pair<Image, OnImageAvailableListener> entry : mImageListenerMap.values()) {
if (entry.first != null) {
entry.first.close();
}
}
mImageListenerMap.clear();
}
}
private class CloseRequestHandler extends CameraCaptureSession.CaptureCallback { private class CloseRequestHandler extends CameraCaptureSession.CaptureCallback {
private final CameraOutputImageCallback mImageCallback;
public CloseRequestHandler(CameraOutputImageCallback imageCallback) {
mImageCallback = imageCallback;
}
@Override @Override
public void onCaptureStarted(@NonNull CameraCaptureSession session, public void onCaptureStarted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
long timestamp, mImageCallback.registerListener(timestamp, new ImageLoopbackCallback());
long frameNumber) {
synchronized (mInterfaceLock) {
mRepeatingRequestImageReader
.setOnImageAvailableListener(new ImageLoopbackCallback(), mHandler);
}
} }
} }
@@ -1187,20 +1290,22 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
private final ExtensionCaptureCallback mCallbacks; private final ExtensionCaptureCallback mCallbacks;
private final CaptureRequest mClientRequest; private final CaptureRequest mClientRequest;
private final boolean mClientNotificationsEnabled; private final boolean mClientNotificationsEnabled;
private ImageReader.OnImageAvailableListener mImageCallback = null; private final CameraOutputImageCallback mRepeatingImageCallback;
private OnImageAvailableListener mImageCallback = null;
private LongSparseArray<Pair<Image, TotalCaptureResult>> mPendingResultMap = private LongSparseArray<Pair<Image, TotalCaptureResult>> mPendingResultMap =
new LongSparseArray<>(); new LongSparseArray<>();
private boolean mRequestUpdatedNeeded = false; private boolean mRequestUpdatedNeeded = false;
public RepeatingRequestHandler(@Nullable CaptureRequest clientRequest, public RepeatingRequestHandler(@Nullable CaptureRequest clientRequest,
@Nullable Executor executor, @Nullable Executor executor, @Nullable ExtensionCaptureCallback listener,
@Nullable ExtensionCaptureCallback listener) { @NonNull CameraOutputImageCallback imageCallback) {
mClientRequest = clientRequest; mClientRequest = clientRequest;
mExecutor = executor; mExecutor = executor;
mCallbacks = listener; mCallbacks = listener;
mClientNotificationsEnabled = mClientNotificationsEnabled =
(mClientRequest != null) && (mExecutor != null) && (mCallbacks != null); (mClientRequest != null) && (mExecutor != null) && (mCallbacks != null);
mRepeatingImageCallback = imageCallback;
} }
@Override @Override
@@ -1226,8 +1331,6 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
new ImageForwardCallback(mRepeatingRequestImageWriter) : new ImageForwardCallback(mRepeatingRequestImageWriter) :
new ImageLoopbackCallback(); new ImageLoopbackCallback();
} }
mRepeatingRequestImageReader
.setOnImageAvailableListener(mImageCallback, mHandler);
} }
} }
@@ -1241,6 +1344,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
} }
mRepeatingImageCallback.registerListener(timestamp, mImageCallback);
} }
@Override @Override
@@ -1248,8 +1353,6 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
int sequenceId) { int sequenceId) {
synchronized (mInterfaceLock) { synchronized (mInterfaceLock) {
if (mInternalRepeatingRequestEnabled) { if (mInternalRepeatingRequestEnabled) {
mRepeatingRequestImageReader.setOnImageAvailableListener(
new ImageLoopbackCallback(), mHandler);
resumeInternalRepeatingRequest(true); resumeInternalRepeatingRequest(true);
} }
} }
@@ -1280,12 +1383,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mRequestUpdatedNeeded = false; mRequestUpdatedNeeded = false;
resumeInternalRepeatingRequest(false); resumeInternalRepeatingRequest(false);
} else if (mInternalRepeatingRequestEnabled) { } else if (mInternalRepeatingRequestEnabled) {
mRepeatingRequestImageReader.setOnImageAvailableListener(
new ImageLoopbackCallback(), mHandler);
resumeInternalRepeatingRequest(true); resumeInternalRepeatingRequest(true);
} else {
mRepeatingRequestImageReader.setOnImageAvailableListener(
new ImageLoopbackCallback(), mHandler);
} }
} }
@@ -1395,12 +1493,14 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
try { try {
if (processStatus) { if (processStatus) {
mExecutor.execute(() -> mCallbacks mExecutor.execute(() -> mCallbacks
.onCaptureProcessStarted(CameraExtensionSessionImpl.this, .onCaptureProcessStarted(
CameraExtensionSessionImpl.this,
mClientRequest)); mClientRequest));
} else { } else {
mExecutor.execute( mExecutor.execute(
() -> mCallbacks () -> mCallbacks
.onCaptureFailed(CameraExtensionSessionImpl.this, .onCaptureFailed(
CameraExtensionSessionImpl.this,
mClientRequest)); mClientRequest));
} }
} finally { } finally {
@@ -1422,7 +1522,8 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
try { try {
if (internal) { if (internal) {
setRepeatingRequest(mPreviewExtender.getCaptureStage(), setRepeatingRequest(mPreviewExtender.getCaptureStage(),
new RepeatingRequestHandler(null, null, null)); new RepeatingRequestHandler(null, null, null,
mRepeatingImageCallback));
} else { } else {
setRepeatingRequest(mPreviewExtender.getCaptureStage(), this); setRepeatingRequest(mPreviewExtender.getCaptureStage(), this);
} }
@@ -1478,26 +1579,20 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} }
} }
private class ImageForwardCallback implements ImageReader.OnImageAvailableListener { private class ImageForwardCallback implements OnImageAvailableListener {
private final ImageWriter mOutputWriter; private final ImageWriter mOutputWriter;
public ImageForwardCallback(@NonNull ImageWriter imageWriter) { public ImageForwardCallback(@NonNull ImageWriter imageWriter) {
mOutputWriter = imageWriter; mOutputWriter = imageWriter;
} }
@Override public void onImageAvailable(ImageReader reader) { @Override
Image img; public void onImageAvailable(ImageReader reader, Image img) {
try {
img = reader.acquireNextImage();
} catch (IllegalStateException e) {
Log.e(TAG, "Failed to acquire and propagate repeating request image!");
return;
}
if (img == null) { if (img == null) {
Log.e(TAG, Log.e(TAG, "Invalid image!");
"Invalid image!");
return; return;
} }
try { try {
mOutputWriter.queueInputImage(img); mOutputWriter.queueInputImage(img);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
@@ -1509,13 +1604,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
} }
} }
private class ImageProcessCallback implements ImageReader.OnImageAvailableListener { private class ImageProcessCallback implements OnImageAvailableListener {
@Override @Override
public void onImageAvailable(ImageReader reader) { public void onImageAvailable(ImageReader reader, Image img) {
Image img; if (mPendingResultMap.size() + 1 >= PREVIEW_QUEUE_SIZE) {
try {
img = reader.acquireNextImage();
} catch (IllegalStateException e) {
// We reached the maximum acquired images limit. This is possible in case we // We reached the maximum acquired images limit. This is possible in case we
// have capture failures that result in absent or missing capture results. In // have capture failures that result in absent or missing capture results. In
// such scenario we can prune the oldest pending buffer. // such scenario we can prune the oldest pending buffer.
@@ -1523,15 +1616,13 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mPendingResultMap mPendingResultMap
.indexOfKey(calculatePruneThreshold(mPendingResultMap)), .indexOfKey(calculatePruneThreshold(mPendingResultMap)),
mPendingResultMap, true); mPendingResultMap, true);
img = reader.acquireNextImage();
} }
if (img == null) { if (img == null) {
Log.e(TAG, Log.e(TAG,
"Invalid preview buffer!"); "Invalid preview buffer!");
return; return;
} }
try { try {
reader.detachImage(img); reader.detachImage(img);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -437,13 +437,11 @@ public class ImageWriter implements AutoCloseable {
// For images from other components that have non-null owner, need to detach first, // For images from other components that have non-null owner, need to detach first,
// then attach. Images without owners must already be attachable. // then attach. Images without owners must already be attachable.
if (!ownedByMe) { if (!ownedByMe) {
if (image.getOwner() == null) { if ((image.getOwner() instanceof ImageReader)) {
} else if ((image.getOwner() instanceof ImageReader)) {
ImageReader prevOwner = (ImageReader) image.getOwner(); ImageReader prevOwner = (ImageReader) image.getOwner();
prevOwner.detachImage(image); prevOwner.detachImage(image);
} else { } else if (image.getOwner() != null) {
throw new IllegalArgumentException("Only images from ImageReader can be queued to" throw new IllegalArgumentException("Only images from ImageReader can be queued to"
+ " ImageWriter, other image source is not supported yet!"); + " ImageWriter, other image source is not supported yet!");
} }