i'm implementing video capture in java program creating bufferedimages @ user-defined interval (for testing, 100ms), , using images make movie file. jframe trying record includes dashboard-like interface contained jlayeredpane. jframe has 2 canvas3ds. i'm telling each of these 3 things render or paint own linkedblockingdeque<bufferedimage>, , combine them later. dashboard set render every dashboardframerepaintfrequency frames.
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(); } { system.err.println("calling getdashboardimage"); m_unsaveddash.add(getdashboardimage(m_dashboard.getwidth(), m_dashboard.getheight(), bufferedimage.type_int_argb)); system.err.println("capturedashboard returned 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(); } } }); i've found after 15-20 notify()s, program locks - stops recording canvases, stops responding keyboard input.. can still change window has focus, , buttons (such x button close window) still change visual state mouse rollover or clicking, don't execute commands.
from console output, seems capturedashboard thread, after 15-20 iterations, not return getdashboardimage method:
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 @ = 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 enlargement } else { scaleop = new affinetransformop(at, affinetransformop.type_bilinear); // better quality ensmallment } scaled = scaleop.filter(original, scaled); original.flush(); return scaled; } any ideas? i've been working @ few days , i'm stumped.
the problem needed call paintall awt dispatch thread.
so instead of:
m_dashboard.paintall(g); i needed have:
final graphics2d g = dashimg.creategraphics(); eventqueue.invokelater(new runnable() { public void run () { m_dashboard.paintall(g); } }); this, however, caused program "get ahead of itself" , return bufferedimage before had been painted to, if program under heavy load. account this, added following:
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(); where syncobj simple:
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(); } } }
Comments
Post a Comment