Skip to main content

Video capture

15 replies [Last post]
pauldb
Offline
Joined: 2003-08-30
Points: 0

Hi,
has anyone successfully created a video (AVI, MPEG etc) from Java3D. I know this topic comes up occassionally but all I see is that people are referred to the J3D.org page on capturing still frames from an offscreen canvas. For video, that page merely suggests using JMF.

Sun's JMF sample pages have an example of creating a video from JPEGs but, as far as I can tell, they need to be at a fixed frame rate. The frames generated from the offscreen canvas will not be at a fixed frame rate.

My ideal would be to create an AVI in real-time (i.e without saving captured JPEGs to disk first) and capturing and synchronising audio with it.

Is this possible? Has anyone done it? If so, how?
(As an aside, I'm sure this would be of interest/value to many people and could appear as a topic on the wiki.)

Many thanks,
-Paul

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Pasi Paasiala

Use java.awt.Robot. We had the same problem some time ago. (Search for Robot
in the forums).

Pasi

_____

From: Alessandro Borges [mailto:alessandroborges@yahoo.com.br]
Sent: 6. huhtikuuta 2006 15:06
To: interest@java3d.dev.java.net
Subject: Re: Video capture

If you are in hurry to produce videos from 3D, you can use fraps.
Run it in a powerful PC, because video encoding is cpu expensive.

www.fraps.com

java3d-interest@javadesktop.org escreveu:

Thank you for your answers!

I also agree it would be a good idea to have a library, an example or an
utility to get video from an animated (or not animated) 3D world. But I
think that Java3D developers are very busy developing enhancements and
fixing bugs... and I need a solution as soon as possible... :(. We can try
to add to this thread all the information we need to get a video.

Don Casteel, I've used your code and I've added a JButton to capture the
image. The problem is that I get a gray image :(. I've also tryed
http://java3d.j3d.org/faq/examples/CapturingCanvas3D.java but I get the same
image. The funniest thing is that sometimes I get a piece of my Netbeans
window!!

Can anyone try the code I posted and the code posted by Don Casteel? Does
anyone know what is happening?

Thanks!
[Message sent by forum member 'ruanonline' (ruanonline)]

http://forums.java.net/jive/thread.jspa?messageID=101396

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

_____

Yahoo! Acesso Grátis
Internet rápida e grátis. Instale

o discador agora!

[att1.html]

ruanonline
Offline
Joined: 2004-12-19
Points: 0

I found a solution!! :).

I use the same Alpha object to control all the interpolators, but I think you can use several Alpha objects.

To get the video I create a JPEG file that represents each video frame.

To get the JPEG file I use the ScreenShot class (and the doRender() method) from the code in http://forums.java.net/jive/thread.jspa?threadID=5092&tstart=120#44205.
I pause the animation at the correct moment depending on the frames per seconds I want, and then I get the screen shot.
Finally, I use the MovieMaker class in this page http://forum.java.sun.com/thread.jspa?forumID=28&threadID=503663 to create the .MOV video. You can create a .AVI video too, but the file will be bigger.

This is mi algorithm:
[code]public static void generateVideo(Canvas3D canvas3D,
long animationTime, Alpha alpha, File outputFile, int fps,
int width, int height) {

/* Initializing the animation */
long startTime = alpha.getStartTime();
alpha.pause(startTime);

/* Milliseconds it takes to change the frame. */
long msFrame = (long)(((float)1/fps)*1000);

/* Frames you need to create the movie */
long framesNeeded = animationTime / msFrame;

/* Create an offscreen canvas from where you'll get the image */
ScreenShot screenShot = new ScreenShot(canvas3D);
canvas3D.getView().addCanvas3D(screenShot);

/*
* CREATE FRAMES
*/

String name = "img_";
String fileType = "jpg";

File fTempDir =
new File(tempDir + System.getProperty("file.separator") + "tempVideo");

Vector vFiles = new Vector();

System.gc();

for(long frameCount = 0; frameCount <= framesNeeded; frameCount++) {
/* Stop the animation in the correct position */
long time = startTime + frameCount * msFrame;
alpha.pause(time);

/* Get the renderized image at that moment */
BufferedImage bi = screenShot.doRender(width, height);

/* Create a JPEG file from the renderized image */
String tempName = name + frameCount;
File file = new File(fTempDir, tempName + "."+ fileType);
try {
ImageIO.write(bi, fileType, file);
} catch (IOException ex) {
ex.printStackTrace();
return;
}

vFiles.add(file);
}

/*
* GENERATE VIDEO
*/

int frameRate = (int)((framesNeeded+1) / (animationTime/1000));

File[] files = vFiles.toArray(new File[0]);

try {
MovieMaker movieMaker = new MovieMaker(width, height, frameRate,
outputFile, files);

movieMaker.makeMovie();
} catch (Exception ex) {
ex.printStackTrace();
}
}[/code]

I know it isn't perfect but it works, I can show you a pair of videos if you want :D.

Good luck!

[b]Update[/b]
You need Java Media Framework to use the MovieMaker class.

Message was edited by: ruanonline

ruanonline
Offline
Joined: 2004-12-19
Points: 0

Thank you for your answers!

I also agree it would be a good idea to have a library, an example or an utility to get video from an animated (or not animated) 3D world. But I think that Java3D developers are very busy developing enhancements and fixing bugs... and I need a solution as soon as possible... :(. We can try to add to this thread all the information we need to get a video.

Don Casteel, I've used your code and I've added a JButton to capture the image. The problem is that I get a gray image :(. I've also tryed http://java3d.j3d.org/faq/examples/CapturingCanvas3D.java but I get the same image. The funniest thing is that sometimes I get a piece of my Netbeans window!!

Can anyone try the code I posted and the code posted by Don Casteel? Does anyone know what is happening?

Thanks!

Alessandro Borges

If you are in hurry to produce videos from 3D, you can use fraps.
Run it in a powerful PC, because video encoding is cpu expensive.

www.fraps.com

java3d-interest@javadesktop.org escreveu: Thank you for your answers!

I also agree it would be a good idea to have a library, an example or an utility to get video from an animated (or not animated) 3D world. But I think that Java3D developers are very busy developing enhancements and fixing bugs... and I need a solution as soon as possible... :(. We can try to add to this thread all the information we need to get a video.

Don Casteel, I've used your code and I've added a JButton to capture the image. The problem is that I get a gray image :(. I've also tryed http://java3d.j3d.org/faq/examples/CapturingCanvas3D.java but I get the same image. The funniest thing is that sometimes I get a piece of my Netbeans window!!

Can anyone try the code I posted and the code posted by Don Casteel? Does anyone know what is happening?

Thanks!
[Message sent by forum member 'ruanonline' (ruanonline)]

http://forums.java.net/jive/thread.jspa?messageID=101396

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

---------------------------------
Yahoo! Acesso Grátis
Internet rápida e grátis. Instale o discador agora!
[att1.html]

Don Casteel

Alessandro,

For some reason I haven't figured out yet, sometimes the first frame of my animations will end up gray, sometimes it doesn't. It has caused me some frustrating do-overs.

you might try doing a repaint, then capture, then repaint.

c.repaint();
c.writeJPEG_ = true;
c.saveJPEG_ = true;
c.repaint();

Donald Casteel

My DeviantArt Gallery
My DeviantArt Home
Apophysis on DeviantArt

---------------------------------
Blab-away for as little as 1¢/min. Make PC-to-Phone Calls using Yahoo! Messenger with Voice.
[att1.html]

ruanonline
Offline
Joined: 2004-12-19
Points: 0

Hello,

I'm also trying to create a video from a 3D scene. I read this thread when you created it but I couldn't ask or try your ideas because I was programming other features of my program, so I added it to my watched topics list.

Now, I've started executing the examples from the JDJ article (http://jdj.sys-con.com/read/99792.htm) and I find a problem. The images I get from the scene when I activate the image capture mode aren't correct. I get a transparent image when I use the PNG format and a black image when I use the JPEG format to save the scene. Sometimes it appears something on the bottom of the image, but it's not an object from the universe.

I've prepared a little example so that you can run it and help me. I'm using the ImageCaptureBehavior class but I've modified it so that it saves the images in a directory called "captured" in the user home directory (C:\Document and Settings\User\captured in Windows 2000/XP or /home/user/captured in Linux). You have to create the "captured" directory.

Thank you in advance!

[code]import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Enumeration;
import javax.imageio.ImageIO;
import javax.media.j3d.*;
import javax.swing.JFrame;
import javax.vecmath.Point3f;

public class ImageCapture extends JFrame {

/** Creates a new instance of Video */
public ImageCapture() {
setLayout(new BorderLayout());
setSize(new Dimension(400, 400));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Canvas3D canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
add(canvas3D, BorderLayout.CENTER);

BranchGroup scene = createSceneGraph();

ImageCaptureBehavior capture = new ImageCaptureBehavior(canvas3D, 0);
capture.setSchedulingBounds(new BoundingSphere());
scene.addChild(capture);

SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
simpleU.getViewingPlatform().setNominalViewingTransform();
simpleU.addBranchGraph(scene);
}

public BranchGroup createSceneGraph() {
BranchGroup objRoot = new BranchGroup();

TransformGroup objSpin = new TransformGroup();
objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRoot.addChild(objSpin);

objSpin.addChild(new ColorCube(0.4));

Alpha rotationAlpha = new Alpha(-1, 4000);

RotationInterpolator rotator =
new RotationInterpolator(rotationAlpha, objSpin);

BoundingSphere bounds = new BoundingSphere();
rotator.setSchedulingBounds(bounds);
objSpin.addChild(rotator);

return objRoot;
}

public static void main(String[] args) {
ImageCapture imageCapture = new ImageCapture();
imageCapture.setVisible(true);
imageCapture.pack();
}
}

class ImageCaptureBehavior extends Behavior {
private Canvas3D canvas;
private String fileType;
private int frameCount = 0;
ImageComponent2D image;
private String location;
private int maximumFrames;
Raster raster;
private WakeupOnElapsedFrames wakeupCondition = null;

public ImageCaptureBehavior(Canvas3D aCanvas, int interval) {
this(aCanvas, interval, 1000);
}

public ImageCaptureBehavior(
Canvas3D aCanvas,
int interval,
int maximumFrames) {
/*this(aCanvas, interval, maximumFrames, "c:\\captured\\", "png");*/
this(aCanvas, interval, maximumFrames,
System.getProperty("user.home")+
System.getProperty("file.separator")+"captured"+
System.getProperty("file.separator"), "png");
}

public ImageCaptureBehavior(
Canvas3D aCanvas,
int interval,
int maximumFrames,
String location,
String fileType) {
canvas = aCanvas;
this.maximumFrames = maximumFrames;
this.location = location;
this.fileType = fileType;
wakeupCondition = new WakeupOnElapsedFrames(interval);
}

private void captureImage(String aName) {
GraphicsContext3D context = canvas.getGraphicsContext3D();
int height = canvas.getBounds().height;
int width = canvas.getBounds().width;
ImageComponent2D image = getImage(height, width);
context.readRaster(getRaster());
BufferedImage bi = (getRaster().getImage()).getImage();
Graphics2D g = bi.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 7);
g.drawString("Copyright (C) 2005, Michael Jacobs", 10,10);
try {
File outfile = new File(location + aName + "." + fileType);
/*String[] formatNames = ImageIO.getWriterFormatNames();*/
ImageIO.write(bi, fileType, outfile);
} catch (Exception e) {
e.printStackTrace();
}
}

protected ImageComponent2D getImage(int height, int width) {
if (image == null) {

BufferedImage bi =
new BufferedImage(height, width, BufferedImage.TYPE_INT_ARGB);

image =
new ImageComponent2D(
ImageComponent2D.FORMAT_RGBA,
bi,
true,
false);
}

return image;
}

protected Raster getRaster() {
if (raster == null) {
int height = canvas.getBounds().height;
int width = canvas.getBounds().width;
raster =
new Raster(
new Point3f(-1.0f, -1.0f, -1.0f),
Raster.RASTER_COLOR,
0,
0,
height,
width,
image,
null);
}
return raster;

}

public void initialize() {
System.out.println("I M A G E C A P T U R E M O D E");
wakeupOn(wakeupCondition);
}

public void processStimulus(Enumeration criteria) {

WakeupCriterion criterion;
while (criteria.hasMoreElements()) {
criterion = (WakeupCriterion) criteria.nextElement();
if (criterion instanceof WakeupOnElapsedFrames) {
captureImage("IMG_" + frameCount);
frameCount++;
if (frameCount % 100 == 0) {
System.out.println(frameCount);
}
}
}
if (frameCount <= maximumFrames) {
wakeupOn(wakeupCondition);
} else {
System.out.println("Maximum number of frames reached");
}

}

}[/code]

Silvère Martin-Michiellot

Hi,

You are approximately number 217 on the list to want to save a video
from Java3D.
Please, please, anyone, put that on the feature list for 1.5 or 1.6 as
part of the utils or whatever but don't let a single more user with this
kind of problem.

Cheers,

Silvere.

java3d-interest@javadesktop.org a écrit :
> Hello,
>
> I'm also trying to create a video from a 3D scene. I read this thread when you created it but I couldn't ask or try your ideas because I was programming other features of my program, so I added it to my watched topics list.
>
> Now, I've started executing the examples from the JDJ article (http://jdj.sys-con.com/read/99792.htm) and I find a problem. The images I get from the scene when I activate the image capture mode aren't correct. I get a transparent image when I use the PNG format and a black image when I use the JPEG format to save the scene. Sometimes it appears something on the bottom of the image, but it's not an object from the universe.
>
> I've prepared a little example so that you can run it and help me. I'm using the ImageCaptureBehavior class but I've modified it so that it saves the images in a directory called "captured" in the user home directory (C:\Document and Settings\User\captured in Windows 2000/XP or /home/user/captured in Linux). You have to create the "captured" directory.
>
> Thank you in advance!
>
> [code]import com.sun.j3d.utils.geometry.ColorCube;
> import com.sun.j3d.utils.universe.SimpleUniverse;
> import java.awt.*;
> import java.awt.image.BufferedImage;
> import java.io.File;
> import java.util.Enumeration;
> import javax.imageio.ImageIO;
> import javax.media.j3d.*;
> import javax.swing.JFrame;
> import javax.vecmath.Point3f;
>
> public class ImageCapture extends JFrame {
>
> /** Creates a new instance of Video */
> public ImageCapture() {
> setLayout(new BorderLayout());
> setSize(new Dimension(400, 400));
> setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
>
> Canvas3D canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
> add(canvas3D, BorderLayout.CENTER);
>
> BranchGroup scene = createSceneGraph();
>
> ImageCaptureBehavior capture = new ImageCaptureBehavior(canvas3D, 0);
> capture.setSchedulingBounds(new BoundingSphere());
> scene.addChild(capture);
>
> SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
> simpleU.getViewingPlatform().setNominalViewingTransform();
> simpleU.addBranchGraph(scene);
> }
>
> public BranchGroup createSceneGraph() {
> BranchGroup objRoot = new BranchGroup();
>
> TransformGroup objSpin = new TransformGroup();
> objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
> objRoot.addChild(objSpin);
>
> objSpin.addChild(new ColorCube(0.4));
>
> Alpha rotationAlpha = new Alpha(-1, 4000);
>
> RotationInterpolator rotator =
> new RotationInterpolator(rotationAlpha, objSpin);
>
> BoundingSphere bounds = new BoundingSphere();
> rotator.setSchedulingBounds(bounds);
> objSpin.addChild(rotator);
>
> return objRoot;
> }
>
> public static void main(String[] args) {
> ImageCapture imageCapture = new ImageCapture();
> imageCapture.setVisible(true);
> imageCapture.pack();
> }
> }
>
> class ImageCaptureBehavior extends Behavior {
> private Canvas3D canvas;
> private String fileType;
> private int frameCount = 0;
> ImageComponent2D image;
> private String location;
> private int maximumFrames;
> Raster raster;
> private WakeupOnElapsedFrames wakeupCondition = null;
>
> public ImageCaptureBehavior(Canvas3D aCanvas, int interval) {
> this(aCanvas, interval, 1000);
> }
>
> public ImageCaptureBehavior(
> Canvas3D aCanvas,
> int interval,
> int maximumFrames) {
> /*this(aCanvas, interval, maximumFrames, "c:\\captured\\", "png");*/
> this(aCanvas, interval, maximumFrames,
> System.getProperty("user.home")+
> System.getProperty("file.separator")+"captured"+
> System.getProperty("file.separator"), "png");
> }
>
> public ImageCaptureBehavior(
> Canvas3D aCanvas,
> int interval,
> int maximumFrames,
> String location,
> String fileType) {
> canvas = aCanvas;
> this.maximumFrames = maximumFrames;
> this.location = location;
> this.fileType = fileType;
> wakeupCondition = new WakeupOnElapsedFrames(interval);
> }
>
> private void captureImage(String aName) {
> GraphicsContext3D context = canvas.getGraphicsContext3D();
> int height = canvas.getBounds().height;
> int width = canvas.getBounds().width;
> ImageComponent2D image = getImage(height, width);
> context.readRaster(getRaster());
> BufferedImage bi = (getRaster().getImage()).getImage();
> Graphics2D g = bi.createGraphics();
> Font font = new Font("Arial", Font.PLAIN, 7);
> g.drawString("Copyright (C) 2005, Michael Jacobs", 10,10);
> try {
> File outfile = new File(location + aName + "." + fileType);
> /*String[] formatNames = ImageIO.getWriterFormatNames();*/
> ImageIO.write(bi, fileType, outfile);
> } catch (Exception e) {
> e.printStackTrace();
> }
> }
>
> protected ImageComponent2D getImage(int height, int width) {
> if (image == null) {
>
> BufferedImage bi =
> new BufferedImage(height, width, BufferedImage.TYPE_INT_ARGB);
>
> image =
> new ImageComponent2D(
> ImageComponent2D.FORMAT_RGBA,
> bi,
> true,
> false);
> }
>
> return image;
> }
>
> protected Raster getRaster() {
> if (raster == null) {
> int height = canvas.getBounds().height;
> int width = canvas.getBounds().width;
> raster =
> new Raster(
> new Point3f(-1.0f, -1.0f, -1.0f),
> Raster.RASTER_COLOR,
> 0,
> 0,
> height,
> width,
> image,
> null);
> }
> return raster;
>
> }
>
> public void initialize() {
> System.out.println("I M A G E C A P T U R E M O D E");
> wakeupOn(wakeupCondition);
> }
>
> public void processStimulus(Enumeration criteria) {
>
> WakeupCriterion criterion;
> while (criteria.hasMoreElements()) {
> criterion = (WakeupCriterion) criteria.nextElement();
> if (criterion instanceof WakeupOnElapsedFrames) {
> captureImage("IMG_" + frameCount);
> frameCount++;
> if (frameCount % 100 == 0) {
> System.out.println(frameCount);
> }
> }
> }
> if (frameCount <= maximumFrames) {
> wakeupOn(wakeupCondition);
> } else {
> System.out.println("Maximum number of frames reached");
> }
>
> }
>
> }[/code]
> [Message sent by forum member 'ruanonline' (ruanonline)]
>
> http://forums.java.net/jive/thread.jspa?messageID=101107
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
> For additional commands, e-mail: interest-help@java3d.dev.java.net
>
>
>
>

--

__________________________________________________________________________________________

Silvere Martin-Michiellot

You will find my latest opensource contribution on www.jscience.org
__________________________________________________________________________________________

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
For additional commands, e-mail: interest-help@java3d.dev.java.net

Don Casteel

First, I agree we need an easy video capture tool.

That said, you have a couple of options. I'm pasting the code for my print/capture canvas3D. I use it exclusevly in the place of the normal Canvas3D. I can't speak for any other operating system but it works great in Windows. Here are a few examples:

http://www.deviantart.com/view/27646633/
http://www.deviantart.com/view/27628447/
http://www.deviantart.com/view/27628229/
http://www.deviantart.com/view/27525558/

Also in Windows, you can always press the PrintScreen button on your keyboard to capture the entire screen to your clipboard, then past it into any graphics paint application, even Windows "Paint". Of course you have to crop accuratly to get a smooth animation.

//--------------------------code below

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.image.*;
import java.awt.print.*;
import java.awt.print.PrinterJob;
import java.awt.print.PrinterGraphics;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.*;
import java.net.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import com.sun.image.codec.jpeg.*;
/** Class PrintCaptureCanvas3D, using the instructions from the Java3D
FAQ pages on how to capture a still image in jpeg format.
A capture button would call a method that looks like
public static void captureImage(PrintCaptureCanvas3D c)
{
c.writeJPEG_ = true;
c.saveJPEG_ = true;
c.repaint();
};
A print button would call a method that looks like
public static void printJPGImage(PrintCaptureCanvas3D c)
{
c.writeJPEG_ = true;
c.saveJPEG_ = false;
c.repaint();
};

Peter Z. Kunszt
Johns Hopkins University
Dept of Physics and Astronomy
Baltimore MD
Working from Mr. Kunszt's posted class, the following enhancements were added:
BufferedImage img; was made global to the class.
The image width was made dynamic using this.getWidth() & this.getHeight() methods.
Printing capability was added (this is still buggy however)
Don Casteel 10/24/1999
doncasteel8587@yahoo.com

*/
public class PrintCaptureCanvas3D extends Canvas3D implements Printable, ImageObserver
{
public boolean swapCompleted = false;
public boolean writeJPEG_;
private int postSwapCount_;
public boolean saveJPEG_;
BufferedImage img;
BufferedImage GIFimg;
FileDialog fileDialog;
File file;
File directory;

public PrintCaptureCanvas3D(GraphicsConfiguration gc)
{
super(gc);
postSwapCount_ = 0;
}
public void addNotify()
{
super.addNotify();
};

public void postSwap()
{
if(writeJPEG_)
{
System.out.println("Writing JPEG");
GraphicsContext3D ctx = getGraphicsContext3D();
// The raster components need all be set!
Raster ras = new Raster
(
new Point3f(-1.0f,-1.0f,-1.0f),
javax.media.j3d.Raster.RASTER_COLOR,
0,0,
this.getWidth(),this.getHeight(),
new ImageComponent2D
(
ImageComponent.FORMAT_RGB,
new BufferedImage
(
this.getWidth(),
this.getHeight(),
BufferedImage.TYPE_INT_RGB
)
),
null
);
ctx.readRaster(ras);
// Now strip out the image info
img = ras.getImage().getImage();
// write that to disk....
if(saveJPEG_)
{
try
{
FileOutputStream out = new FileOutputStream("Capture"+postSwapCount_+".jpg");
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(img);
param.setQuality(0.9f,false); // 90% qualith JPEG
encoder.setJPEGEncodeParam(param);
encoder.encode(img);
writeJPEG_ = false;
out.close();
}
catch ( IOException e )
{
System.out.println("I/O exception!");
};
}
else
{
printMethod();
writeJPEG_ = false;
};
postSwapCount_++;
}
swapCompleted = true;
};
public int print(Graphics g, PageFormat pf, int pi)
throws PrinterException
{
if (pi >= 1)
{
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
drawObject(g2d);
return Printable.PAGE_EXISTS;
};
public void drawObject(Graphics2D g2d)
{
try
{
g2d.drawImage(img,new AffineTransform(), this);
}
catch (Exception ex)
{
ex.printStackTrace();
};
};
public void printMethod()
{
System.out.println("Print Method Called");
PrinterJob printJob = PrinterJob.getPrinterJob();
PageFormat pageFormat = printJob.defaultPage();
pageFormat = printJob.validatePage(pageFormat);
printJob.setPrintable(this);
if (printJob.printDialog())
{
try
{
printJob.print();
}
catch (Exception ex)
{
System.out.println("Exception Caught");
ex.printStackTrace();
};
};
};
}

Donald Casteel

My DeviantArt Gallery
My DeviantArt Home
Apophysis on DeviantArt

---------------------------------
New Yahoo! Messenger with Voice. Call regular phones from your PC and save big.
[att1.html]

mnjacobs
Offline
Joined: 2003-06-13
Points: 0

Paul, I have been creating MPEG movies from captured frames for a while now.

> The frames generated
> from the offscreen canvas will not be at a fixed
> frame rate.

They can be forced to be a fixed rate. Typically, a scene is updated by a behavior that triggers every frame. In this animation behavior, a time differential from the last frame is determined and passed to the scene update code. This is done so that smooth animation can be done based on the velocity and acceleration of the objects in the scene.

The animation behavior can have a check that determines if it is in 'scene capture mode'. In this mode, the time difference sent to the scene update code is a fixed value (an thus a fixed frame rate). This can be as simple as checking to see if the elapsed time exceeds a certain value. Screen capturing is at non-interactive rates so this approach seems to work.

A second behavior can be triggered every frame to capture the canvas image and store it.

Once the frames are captured, a post production step is needed to build the video. I happen to use VideoMach (http://www.gromada.com/) because it does exactly what I need and not much more (and it's affordable).

I can post example behaviors if you need them.

Mike

pauldb
Offline
Joined: 2003-08-30
Points: 0

Hi Mike,
I'd really like to see your behaviors - that would be great. Thanks. I'll send you my email address.
-Paul

mnjacobs
Offline
Joined: 2003-06-13
Points: 0

Paul, Here are two behaviors that were part of distribution for a JDJ article (http://jdj.sys-con.com/read/99792.htm). A few caveats:

* The ParticleSystemManager is the main clock behavior that is activated every frame.
* The ImageCaptureBehavior captures every frame and has a few hardcoded assumptions.
* The coloring of the code /code tags are not my doing, honest.

There is no scheduling interval used so in theory they could run out of order. If you have more than one other behavior that runs every frame, look into how to use Behavior scheduling intervals.

[code]
package particles;
import java.awt.AWTEvent;
import java.util.Enumeration;

import javax.media.j3d.*;
import com.sun.j3d.utils.timer.*;
import java.util.*;

public class ParticleSystemManager extends Behavior {
private static ParticleSystemManager current;
private Collection listeners;
private WakeupCondition wakeupCondition = null;
private long lastTime = 0;
float frameCycleTime = 0;

public static ParticleSystemManager getCurrent(float cycleTime){
if(current == null){
current = new ParticleSystemManager(cycleTime);
}
return current;
}

public static ParticleSystemManager getCurrent(){
return getCurrent(0.033f);
}

public ParticleSystemManager(float frameCycleTime) {
this.frameCycleTime = frameCycleTime;
}

private Collection getListeners(){
if(listeners == null){
listeners = new Vector();
}
return listeners;
}

private WakeupCondition getMyWakeupCondition(){
if(wakeupCondition == null){
wakeupCondition = new WakeupOnElapsedFrames(0);
}
return wakeupCondition;
}

public void initialize() {
wakeupOn(getMyWakeupCondition());
lastTime = System.currentTimeMillis();
}

private void notifyListeners(Collection c, float dt){
Iterator iterator = c.iterator();
while(iterator.hasNext()){
IParticleSystem ps = (IParticleSystem)iterator.next();
ps.nextFrame(dt);
}
}

public void processStimulus(Enumeration criteria) {
WakeupCriterion criterion;
AWTEvent[] events;
wakeupOn(getMyWakeupCondition());
while (criteria.hasMoreElements()) {
criterion = (WakeupCriterion) criteria.nextElement();
long currentTime = System.currentTimeMillis();
float dt = Math.min(((float)(currentTime - lastTime))/1000, frameCycleTime);
lastTime = currentTime;
notifyListeners(getListeners(), dt);
}

}

public void register(IParticleSystem aParticleSystem){
getListeners().add(aParticleSystem);
}
}

[/code]

[code]
package particles.examples;
import javax.media.j3d.*;
import java.util.Enumeration;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.*;
import javax.media.j3d.*;
import javax.vecmath.*;

import javax.media.j3d.Behavior;

public class ImageCaptureBehavior extends Behavior {
private Canvas3D canvas;
private String fileType;
private int frameCount = 0;
ImageComponent2D image;
private String location;
private int maximumFrames;
Raster raster;
private WakeupOnElapsedFrames wakeupCondition = null;

public ImageCaptureBehavior(Canvas3D aCanvas, int interval) {
this(aCanvas, interval, 1000);
}

public ImageCaptureBehavior(
Canvas3D aCanvas,
int interval,
int maximumFrames) {
this(aCanvas, interval, maximumFrames, "c:\\captured\\", "png");
}

public ImageCaptureBehavior(
Canvas3D aCanvas,
int interval,
int maximumFrames,
String location,
String fileType) {
canvas = aCanvas;
this.maximumFrames = maximumFrames;
this.location = location;
this.fileType = fileType;
wakeupCondition = new WakeupOnElapsedFrames(interval);
}

private void captureImage(String aName) {
GraphicsContext3D context = canvas.getGraphicsContext3D();
int height = canvas.getBounds().height;
int width = canvas.getBounds().width;
ImageComponent2D image = getImage(height, width);
context.readRaster(getRaster());
BufferedImage bi = (getRaster().getImage()).getImage();
Graphics2D g = bi.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 7);
g.drawString("Copyright (C) 2005, Michael Jacobs", 10,10);
try {
File outfile = new File(location + aName + "." + fileType);
//String[] formatNames = ImageIO.getWriterFormatNames();
ImageIO.write(bi, fileType, outfile);
} catch (Exception e) {
e.printStackTrace();
}
}

protected ImageComponent2D getImage(int height, int width) {
if (image == null) {

BufferedImage bi =
new BufferedImage(height, width, BufferedImage.TYPE_INT_ARGB);

image =
new ImageComponent2D(
ImageComponent2D.FORMAT_RGBA,
bi,
true,
false);
}

return image;
}

protected Raster getRaster() {
if (raster == null) {
int height = canvas.getBounds().height;
int width = canvas.getBounds().width;
raster =
new Raster(
new Point3f(-1.0f, -1.0f, -1.0f),
Raster.RASTER_COLOR,
0,
0,
height,
width,
image,
null);
}
return raster;

}

public void initialize() {
System.out.println("I M A G E C A P T U R E M O D E");
wakeupOn(wakeupCondition);
}

public void processStimulus(Enumeration criteria) {

WakeupCriterion criterion;
while (criteria.hasMoreElements()) {
criterion = (WakeupCriterion) criteria.nextElement();
if (criterion instanceof WakeupOnElapsedFrames) {
captureImage("IMG_" + frameCount);
frameCount++;
if (frameCount % 100 == 0) {
System.out.println(frameCount);
}
}
}
if (frameCount <= maximumFrames) {
wakeupOn(wakeupCondition);
} else {
System.out.println("Maximum number of frames reached");
}

}

}
[/code]

pauldb
Offline
Joined: 2003-08-30
Points: 0

That's fantastic, Mike. Many many thanks for that.
It's given me a great start.

I do need to capture and synchronise with audio though.
Does anyone else have experience of doing synchronised video and audio capture in Java3D?

I've read that you can merge datasources in JMF but this would have to be done in real-time. So, I'm wondering about performance of that compared with grabbing a series of screens and converting them into movie form later.

Thanks,
-Paul

pauldb
Offline
Joined: 2003-08-30
Points: 0

Just wondering...

Has anyone tried video capture with Java3D using java.awt.Robot as in the JMF example?

Seems an obvious route but what is the FPS performance?

-Paul

shawnkendall
Offline
Joined: 2003-06-10
Points: 0

Game review sites have to capture video and audio, and even include video reviews now.
Of course, they are doing the capture from the video output (including high rez), and frankly that is the best way to do this because it will show the truest refresh rate and look of the 3d app because it will not tax the machine doing the rendering.

I highly suggest that kind of set up if you can get some more hardware...

pauldb
Offline
Joined: 2003-08-30
Points: 0

Hi Shawn,
I can't really; this is for a consumer product. At the moment, I reccommend FRAPS video capture software for anyone who wants to capture a video playback. However, I really need something "built-in", so I'm looking for the best way to go.

Thanks for your interest though,
-Paul