3

BufferedImageユーザー定義の間隔 (私のテストでは 100 ミリ秒) で s を作成し、それらの画像を使用してムービー ファイルを作成することにより、Java プログラムでビデオ キャプチャを実装しています。JFrameから記録しようとしている には、 に含まれるダッシュボードのようなインターフェイスが含まれていますJLayeredPane。にJFrameも 2 つCanvas3Dの があります。私はこれら 3 つのことをそれぞれ独自のに、renderまたは独自の に伝えており、後でそれらを結合します。ダッシュボードは、すべてのフレームのみをレンダリングするように設定されています。paintLinkedBlockingDeque<BufferedImage>dashboardFrameRepaintFrequency

Thread captureThread = new Thread(new Runnable() {
    public void run() {
        final Object LOCK = new Object();
            final Thread captureDashboard = new Thread(new Runnable() {
                public void run() {
                    while (m_isCapturingMovie) {
                        synchronized (LOCK) {
                            try {
                                LOCK.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } finally {
                                System.err.println("Calling getDashboardImage");
                                m_unsavedDash.add(getDashboardImage(m_dashboard.getWidth(), m_dashboard.getHeight(), BufferedImage.TYPE_INT_ARGB));
                                System.err.println("captureDashboard returned from calling m_unsavedDash.add...");
                            }
                        }
                    }
                }
            });
            captureDashboard.start();

            while (m_isCapturingMovie) {
                startTime = System.currentTimeMillis();
                captureCanvases();
                if (++frameCount > dashboardFrameRepaintFrequency) {
                    frameCount = 0;
                    synchronized (LOCK) {
                        LOCK.notify();
                    }
            }
            endTime = System.currentTimeMillis();
            millisToSleep = captureDelayInMillis - (endTime - startTime);
            if (millisToSleep > 0) {
                try {
                    Thread.sleep(millisToSleep);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        synchronized (captureDashboard) {
        captureDashboard.notify();
        }
    }
});

15 ~ 20notify()秒後に、プログラムがロックアップすることがわかりました。キャンバスの記録が停止し、キーボード入力への応答が停止します。まだ、フォーカスのあるウィンドウとボタン (ウィンドウを閉じるための X ボタンなど) を変更できます。 window) は、マウスのロールオーバーやクリックによって視覚状態を変更しますが、コマンドを実行しません。

コンソール出力から、15 ~ 20 回の反復の後、captureDashboard スレッドがgetDashboardImageメソッドから返されないようです。

private BufferedImage getDashboardImage(int width, int height, int type) {
    BufferedImage dashImg = new BufferedImage(m_dashboard.getWidth(), m_dashboard.getHeight(), type);
    Graphics2D g = dashImg.createGraphics();
    m_dashboard.paintAll(g);
    g.dispose();

    return getScaledImage(width, height, dashImg);
}

private BufferedImage getScaledImage(int width, int height, BufferedImage original) {
    BufferedImage scaled = new BufferedImage(width, height, original.getType());

    AffineTransform at = new AffineTransform();
    at.scale((double) scaled.getWidth() / original.getWidth(), (double) scaled.getHeight() / original.getHeight());
    AffineTransformOp scaleOp;
    if (at.getScaleX() + at.getScaleY() > 2.0) {
        scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC); // Better quality for enlargement
    } else {
        scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); // Better quality for ensmallment
    }

    scaled = scaleOp.filter(original, scaled);
    original.flush();
    return scaled;
}

何か案は?私はこれで数日間働いていて、困惑しています。

4

1 に答える 1

1

paintAll問題は、AWT ディスパッチ スレッドから呼び出す必要があることでした。

したがって、代わりに:

m_dashboard.paintAll(g);

私が持っている必要がありました:

final Graphics2D g = dashImg.createGraphics();

EventQueue.invokeLater(new Runnable() {
    public void run () {
        m_dashboard.paintAll(g);
    }
});

ただし、これにより、プログラムが「先に進み」、BufferedImageペイントされる前に戻りますが、プログラムの負荷が高い場合にのみです。これを説明するために、以下を追加しました。

final Graphics2D g = dashImg.createGraphics();
final SyncObj LOCK = new SyncObj();

EventQueue.invokeLater(new Runnable() {
    public void run () {
        m_dashboard.paintAll(g);
        LOCK.doNotify();
    }
});

LOCK.doWait();
g.dispose();

SyncObj は単純なものです。

class SyncObj {
    private boolean condition = false;
    private Object obj = new Object();

    public void doWait() {
        synchronized (obj) {
            while (!condition) {
                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            condition = false;
        }
    }

    public void doNotify() {
        synchronized (obj) {
            condition = true;
            obj.notify();
        }
    }
}
于 2013-07-22T15:03:38.490 に答える