Merge "Fix ImageReader onImageAvailable synchronization" into klp-dev
This commit is contained in:
@@ -20,6 +20,7 @@ import android.graphics.ImageFormat;
|
|||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@@ -377,17 +378,21 @@ public class ImageReader implements AutoCloseable {
|
|||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* If no handler specified and the calling thread has no looper.
|
* If no handler specified and the calling thread has no looper.
|
||||||
*/
|
*/
|
||||||
public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
|
public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
|
||||||
mImageListener = listener;
|
synchronized (mListenerLock) {
|
||||||
|
if (listener != null) {
|
||||||
Looper looper;
|
Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
|
||||||
mHandler = handler;
|
if (looper == null) {
|
||||||
if (listener != null && mHandler == null) {
|
throw new IllegalArgumentException(
|
||||||
if ((looper = Looper.myLooper()) != null) {
|
"handler is null but the current thread is not a looper");
|
||||||
mHandler = new Handler();
|
}
|
||||||
|
if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
|
||||||
|
mListenerHandler = new ListenerHandler(looper);
|
||||||
|
}
|
||||||
|
mListener = listener;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException(
|
mListener = null;
|
||||||
"Looper doesn't exist in the calling thread");
|
mListenerHandler = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -426,6 +431,7 @@ public class ImageReader implements AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
setOnImageAvailableListener(null, null);
|
||||||
nativeClose();
|
nativeClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,6 +480,9 @@ public class ImageReader implements AutoCloseable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from Native code when an Event happens.
|
* Called from Native code when an Event happens.
|
||||||
|
*
|
||||||
|
* This may be called from an arbitrary Binder thread, so access to the ImageReader must be
|
||||||
|
* synchronized appropriately.
|
||||||
*/
|
*/
|
||||||
private static void postEventFromNative(Object selfRef) {
|
private static void postEventFromNative(Object selfRef) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@@ -483,16 +492,16 @@ public class ImageReader implements AutoCloseable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ir.mHandler != null && ir.mImageListener != null) {
|
final Handler handler;
|
||||||
ir.mHandler.post(new Runnable() {
|
synchronized (ir.mListenerLock) {
|
||||||
@Override
|
handler = ir.mListenerHandler;
|
||||||
public void run() {
|
}
|
||||||
ir.mImageListener.onImageAvailable(ir);
|
if (handler != null) {
|
||||||
}
|
handler.sendEmptyMessage(0);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final int mWidth;
|
private final int mWidth;
|
||||||
private final int mHeight;
|
private final int mHeight;
|
||||||
private final int mFormat;
|
private final int mFormat;
|
||||||
@@ -500,14 +509,35 @@ public class ImageReader implements AutoCloseable {
|
|||||||
private final int mNumPlanes;
|
private final int mNumPlanes;
|
||||||
private final Surface mSurface;
|
private final Surface mSurface;
|
||||||
|
|
||||||
private Handler mHandler;
|
private final Object mListenerLock = new Object();
|
||||||
private OnImageAvailableListener mImageListener;
|
private OnImageAvailableListener mListener;
|
||||||
|
private ListenerHandler mListenerHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This field is used by native code, do not access or modify.
|
* This field is used by native code, do not access or modify.
|
||||||
*/
|
*/
|
||||||
private long mNativeContext;
|
private long mNativeContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
|
||||||
|
*/
|
||||||
|
private final class ListenerHandler extends Handler {
|
||||||
|
public ListenerHandler(Looper looper) {
|
||||||
|
super(looper, null, true /*async*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
OnImageAvailableListener listener;
|
||||||
|
synchronized (mListenerLock) {
|
||||||
|
listener = mListener;
|
||||||
|
}
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onImageAvailable(ImageReader.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class SurfaceImage extends android.media.Image {
|
private class SurfaceImage extends android.media.Image {
|
||||||
public SurfaceImage() {
|
public SurfaceImage() {
|
||||||
mIsImageValid = false;
|
mIsImageValid = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user