我正在创建一个实时流媒体应用程序,但在某个时候遇到了困难。
所以,这是我的代码:

public synchronized byte[] getPicture(int Width, int Height) {
    FrameWidth = Width;
    FrameHeight = Height;

    try {
        while (!isPreviewOn) {
            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();
    }
};


当调用了同步getPicture()时,在执行过程中,没有其他线程可以在该实例上调用同步方法。当getPicture()等待isDecoding时,它将在实例上持有一个锁。我怀疑setOneShotPreviewCallback()正在执行,并且摄像头正在尝试在其自己的线程上调用onPreviewFrame(),但是由于这也是一个同步方法,因此它阻塞了等待getPicture()终止的过程,因为它需要回调才能终止清除isDecoding。看起来像是僵局。

它无法调用onPreviewFrame,因为对象实例已锁定,因此相机线程被阻塞,等待getPicture()完成。

我对么?
我该如何解决呢?所以我必须再次通知OnPreviewFrame IsDecoding = false

很感谢任何形式的帮助。

还要对此投票,我将提供赏金;)

最佳答案

mPreviewCallback.onPreviewFrame()中的notify()通知mPreviewCallback对象监视器,而getPicture()中的wait()等待另一个对象监视器-notify永远不会释放wait()。您应该定义两个对象都可以访问的(最终)变量,并在该变量上显式调用wait()和notify()。像这样:

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


我不知道您要扩展的API,但是更改之后,可能不需要同步进程。另外,不清楚谁在设置isPreviewOn。

09-07 17:55