Need help with Synchronized
I am creating a live streaming app, but I'm stuck at a certain point. So, this is my code:
public synchronized byte[] getPicture(int Width, int Height) {
FrameWidth = Width;
FrameHeight = Height;
try {
while (!isPrevie开发者_如何学JAVAwOn) {
wait();
}
isDecoding = true;
mAvailableFrame = false;
c.setOneShotPreviewCallback(mPreviewCallback);
while (isDecoding) {
wait();
}
}
catch (Exception e) {
return null;
}
mAvailableFrame = false;
return mCurrentFrame;
}
PreviewCallback mPreviewCallback = new PreviewCallback() {
@Override
public synchronized void onPreviewFrame(byte[] data, Camera camera) {
int width = FrameWidth;
int height = FrameHeight;
// API 7
int[] temp = new int[width*height];
OutputStream out = new ByteArrayOutputStream();
Bitmap bm = null;
raw2jpg(temp, data, width, height);
bm = Bitmap.createBitmap(temp, width, height, Bitmap.Config.RGB_565);
bm.compress(CompressFormat.JPEG, 100, out);
/*ref*/mCurrentFrame = ((ByteArrayOutputStream)out).toByteArray();
mAvailableFrame = true;
isDecoding = false;
notify();
}
};
When synchronised getPicture() is called, while it is executing no other thread can call a synchronised method on that instance. While getPicture() is waiting for isDecoding it is holding a lock on the instance. I suspect setOneShotPreviewCallback() is executing and that the camera is trying to call onPreviewFrame() on its own thread but as that is also a synchronised method it blocks waiting for getPicture() to terminate which it can't as it needs the callback to clear isDecoding. It looks like a deadlock situation.
It can't call onPreviewFrame because the object instance is locked so the camera thread is blocked waiting for getPicture() to complete.
Am I correct? And how should I fix this? So I have to notify OnPreviewFrame again that IsDecoding = false
Any help is very much appreciated.
Also vote this up and I will give a bounty ;)
The notify() in mPreviewCallback.onPreviewFrame() notifies the mPreviewCallback object monitor, while wait() in getPicture() waits on another object monitor - notify will never release wait(). You should define a (final) variable accessible from both objects and call wait() and notify() explicitly on that variable. Something like this:
public final Object myMonitor = new Object();
public synchronized byte[] getPicture(int Width, int Height) {
FrameWidth = Width;
FrameHeight = Height;
try {
synchronized(myMonitor) {
while (!isPreviewOn) {
myMonitor.wait();
}
}
isDecoding = true;
mAvailableFrame = false;
c.setOneShotPreviewCallback(mPreviewCallback);
synchronized(myMonitor) {
while (isDecoding) {
myMonitor.wait();
}
}
}
catch (Exception e) {
return null;
}
mAvailableFrame = false;
return mCurrentFrame;
}
PreviewCallback mPreviewCallback = new PreviewCallback() {
@Override
public synchronized void onPreviewFrame(byte[] data, Camera camera) {
int width = FrameWidth;
int height = FrameHeight;
// API 7
int[] temp = new int[width*height];
OutputStream out = new ByteArrayOutputStream();
Bitmap bm = null;
raw2jpg(temp, data, width, height);
bm = Bitmap.createBitmap(temp, width, height, Bitmap.Config.RGB_565);
bm.compress(CompressFormat.JPEG, 100, out);
/*ref*/mCurrentFrame = ((ByteArrayOutputStream)out).toByteArray();
mAvailableFrame = true;
isDecoding = false;
synchronized(myMonitor) {
myMonitor.notify();
}
}
};
I don't know the API you are extending, but probably the processes won't need to be synchronized after this change. Also, it is not clear who is setting isPreviewOn.
精彩评论