drop-in image sequence sketch capture for 2.0 OGL
in
Share your Work
•
1 year ago
I am tinkering with a method to capture video output from Processing sketches using a TGA image sequence and its starting to show promise. Creating a new tab in any P3D (OpenGL) sketch and adding the following code automatically sends the raw visual output of the sketch to a single file overwriting it with each new frame. Running the second piece of code from a separate PDE (separate process) begins reading the raw data in the file once each time the draw loop runs and saving each frame to a separate TGA file.
I have tried to make it as efficient as possible to enable the capture of interactive sketches without excessive slowdown. I have not tested this code heavily and it is still somewhat unfinished and uncommented.
I have tried to make it as efficient as possible to enable the capture of interactive sketches without excessive slowdown. I have not tested this code heavily and it is still somewhat unfinished and uncommented.
- Using Processing's smooth(...) method causes an error (from JOGL I believe "cannot lock native surface" or something like that). On Windows you can work around this by adding a profile in NVidia control panel for the java.exe that Processing is using and setting anti-aliasing options there. I believe AMD has something similar.
- It looks like there are some dropped frames between the first and the second captured frames. I have not looked into it yet. Past that the capture rate seems to be quite consistent.
- I have occasionally seen glitches in the output TGAs of one of my testing setups. It seems to either affect most of the frames of a run or none. Have not tried to fix it yet.
- Be sure to close fileCapSave.pde with the window button. It waits a second to make sure the final frame is properly written.
fileCapSend.pde
add this to a new tab in the sketch you want to capture from
add this to a new PDE, make sure the tmpLoc variable (points to the temp file) is the same here and in fileCapSend.pde, also set ww and hh to the width and height of the sketch you are capturing and change the saveLoc (location where frames will be saved, default is [fileCapSave.pde sketchPath]\test\) if you want
add this to a new tab in the sketch you want to capture from
PApplet fileCapSendPAppletRef; { import javax.media.opengl.GLContext; import javax.media.opengl.GL; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; fileCapSendPAppletRef = this; new Thread(new Runnable() { public void run() { while(frameCount < 1) {} new FileCapSend(); } }).start(); } public class FileCapSend { class SendThread extends Thread { public void run() { for(;;) { if(!run) break; if(cap) { glc.makeCurrent(); gl.glReadPixels( 0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, bb); glc.release(); try { fc.write(bb); fc.position(0); } catch(Throwable fex) {fex.printStackTrace();} bb.clear(); cap = false; } else { try { sleep(1); } catch(Throwable ex) {ex.printStackTrace();} } } } } PApplet p5; PGraphicsOpenGL pg; GLContext glc; GL gl; ByteBuffer bb; String tmpLoc = "C:\\p5tmp"; FileChannel fc; boolean run = true; boolean registered, cap; SendThread sendThread; FileCapSend() { p5 = fileCapSendPAppletRef; pg = (PGraphicsOpenGL)p5.g; glc = pg.pgl.context; gl = pg.pgl.gl; bb = ByteBuffer.allocateDirect(width*height*4); if(run) beginCap(); } void beginCap() { try { File prev = new File(tmpLoc); if(prev.exists()) prev.delete(); fc = new RandomAccessFile(tmpLoc, "rw").getChannel(); } catch(Throwable ex) { ex.printStackTrace(); run = false; return; } sendThread = new SendThread(); sendThread.start(); register(); } void register() { p5.registerPost(this); registered = true; } void endCap() { p5.unregisterPost(this); try { fc.close(); } catch(Throwable ex) {ex.printStackTrace();} } public void post() { if(!run && registered) { endCap(); return; } cap = true; } }fileCapSave.pde
add this to a new PDE, make sure the tmpLoc variable (points to the temp file) is the same here and in fileCapSend.pde, also set ww and hh to the width and height of the sketch you are capturing and change the saveLoc (location where frames will be saved, default is [fileCapSave.pde sketchPath]\test\) if you want
import processing.opengl.PGL; import java.nio.ByteOrder; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; int ww = 1280; int hh = 720; String tmpLoc = "C:\\p5tmp"; String saveLoc = sketchPath("test\\"); ByteBuffer bb; FileChannel fc; int ind = -1; PImage pi; void setup() { try { fc = new RandomAccessFile(tmpLoc, "rw").getChannel(); fc.map(FileChannel.MapMode.READ_ONLY, 0, ww*hh*4); bb = ByteBuffer.allocateDirect(ww*hh*4); bb.order(ByteOrder.nativeOrder()); } catch(Throwable ex) {ex.printStackTrace();} pi = createImage(1280,720,RGB); pi.loadPixels(); } void draw() { ind++; try { fc.position(0); fc.read(bb); } catch(Throwable ex) {ex.printStackTrace();} regularSave(); bb.clear(); } void regularSave() { bb.rewind(); bb.asIntBuffer().get(pi.pixels); PGL.nativeToJavaRGB(pi.pixels, ww, hh); pi.save(saveLoc+nf(ind, 6)+".tga"); } void exit() { try { Thread.currentThread().sleep(500); } catch(Throwable ex) {} super.exit(); }