It turns out I can create those movies in Java pretty easily. I made an application that ties into the RepaintManager (and listens for MouseEvents and ComponentEvents), and with that I'm able to get anywhere between 5 and 90 fps as I capture data using the Robot class.
Because I'm only capturing the parts of the window that are dirty, the size of your window doesn't matter: it's how much activity is taking place that counts. (Well, that and your processor speed. And RAM.)
Here is a demo of what this program can do:
Is it perfect? No. In my opinion the biggest two drawbacks are:
Also the mouse location sometimes is recorded out-of-whack (there are at least 2 parts in the demo movie where the mouse "jumps" for a fraction of a second).
So... whatever it's shortcomings may be: here is the demo program that captured the video above. Note it is bundled with my previous blog entry so it can write MOV files, but you're welcome to remove those classes if there's another way you'd like to encode the animation. (The animation is iterated through as a series of BufferedImages, so you can do whatever you like with it.)
(In the interest of full disclosure, I should point out the movie on this webpage was NOT directly created by this app. To publish the movie for the web, I re-encoded the movie this application created using MPEG-4 level compression.)
Also a truly professional-looking tutorial movie will not really record every mouse movement the user makes: it will smooth out your gestures to give you a super-human grace. (There will be no wobbly bits, no corrections, etc.). I suppose that wouldn't be too hard to do in this package: so long as you knew exactly where the start/stop points for a mouse gesture were...

First off, thanks for sharing the source for this. It's really interesting. My biggest question is about using Robot for capturing pixels, instead of getting the pixels from something that already has them like a top-level component or RepaintManager. I couldn't find any API that would definitely work for this, but get[Volatile]OffscreenBuffer might be what I want. Going this route would have two advantages over Robot:
ReplyDelete1) It would probably be faster
2) It wouldn't be disrupted by any obscuring windows.
If anybody has suggestions on this, please post them.
Hmmm. Good point. The RepaintManager wouldn't handle pixels, but what would happen if you simply asked the topmost frame to paint a particular rectangle?
ReplyDeleteI'm not convinced this would be faster, though, but I'd have to check. But for the time being this is one of several projects to live on the back-burner until I'm ready to make some tutorial movies. :) If you make any findings I'd love to hear about them, though.
Pretty damn'd neat. I'm going to use it for a plugin of my application, it would make my beta users' life easier when they report a bug, so they don't have to install and tweak with an external screen recorder.
ReplyDeleteThe first integration was neat, but I see that sometimes the application gets really slowed down. I suspect that it's related to some video effects such as fade-in/fade-out that can involve a burst of full repaints of the whole window. In any case, I think it makes sense to disable them while recording. I'll let you know.
Great Way to record things, Have one question...Is the movie encoder in pure java ...so basically is it cross platform
ReplyDeleteYes, everything is pure Java. I think the biggest cross platform issue with it is that the performance of Robot. It's fast enough on OS X and Windows, but I haven't actually tested elsewhere. I think there is still an open Bug Parade bug complaining about Linux Robot speed.
ReplyDeleteGreat article! I think i'll have to check that out on some of my latest stuff. I also noticed theres a whole host of other apps on the web. Try:
ReplyDeletehttp://www.accelerated-ideas.com/SoftwareDownload/prod-screen-capture.aspx
This is true. I'm a fan of Jing personally (it's free), but last I knew it didn't offer QT movie export -- which is a pity because I was looking for something that would integrate really well with iLife.
ReplyDeleteBut this article is not meant to be (or compete with) stand-alone screen capture apps... it's just a starting point with working source code for developers who want/need to a do-it-yourself approach.
Would you be willing to share the source code for this?
ReplyDeleteThe source code is included in the jar. (All my blog articles should be open-source... if you have trouble finding the code for any of them feel free to email me directly.)
ReplyDeletedo you know of any way to capture the entire screen
ReplyDeleteThe Robot class (which is what this project ultimately uses) can capture the entire screen (minus the cursor). However you'll probably have a hard time capturing things at a decent frame rate with images that size.
ReplyDeleteThe novelty of the approach in this article is that only the dirty parts of the window are captured, so it's reasonably fast.
Hi Jeremy,
ReplyDeleteGreat post and code.
One thing I've noticed with your code and my own (I'm writing a very similar application) is that performance is a big issue with calls to ImageIO.read and ImageIO.write.
Both your project and mine seem to struggle with anything more than a minute or 2 and compilation sometimes takes double the time of the video itself.
Have you experienced the same thing? Again, I'm not knocking your code at all, I think its great and had a great time reading through it. But I've written similar (not nearly as robust) code and have had the same hangups with ImageIO.
Is it a hardware issue? ie are we stuck with the speeds our hard disks can read/write? Or is there something more we can do to make these writes faster?
The reads aren't as much of an issue since there aren't nearly as many.
Cheers,
Gary
You're absolutely right, Gary. But I don't have a silver bullet in mind to speed up the encoding process. Surely there are faster ways to encode movie data (in this case we're just encoding JPEGs), but I don't know if there are faster pure-Java ways.
ReplyDeleteIn my case: I wasn't envisioning the encoding process as something my users are going to suffer through, so I wasn't too worried about it. I would be making these movies for them: they would not make them for me.
I guess if you're willing to ignore the movie's file size: you could encode the images as uncompressed PNGs? Then the bottleneck would mostly be piping the frames into the movie file.
can't we somehow convert the captures into a stream of video and use the JMF i.e. Java Media Framework API to tranmit our screen happenings, like VNC does
ReplyDeleteA,
ReplyDeleteThe current implementation uses a AnimationReader object to iterate over a series of frames as BufferedImages when you stop recording. This is because processing these frames is expensive, and I wanted the lightest possible load on the CPU while the app is recording. (Although, as Gary pointed out: this can result in some awful encoding delays once recording stops.)
If your goal is to stream the incoming frames live: it's certainly possible, but you'll have to rewrite large portions of the code. As you do this keep an eye on performance, though, and make sure it stays acceptable on your target platforms.
Personally I would not recommend using JMF for this. (Has it been updated since 2003?) But this project deals with BufferedImages and pixels, so you can use JMF, QTJ, Transform, or any number of other packages to process the frames as you see fit.
If anyone does successfully adapt this code: feel free to post a reference to it here.
I tried this under Ubuntu Linux 9.10 and crashed at the very end of the encoding process.
ReplyDeleteAnonymous,
ReplyDeleteWell, the good news is that the screen-capture mechanism is probably working.
If I had to guess: it sounds like the RandomAccessFile used in the JPEGMovieAnimation crashes on your platform. If you get in touch with me via email I might be able to help get to the bottom of this.
OK. I have a new hackintosh now, and It works like a dream. I'm going to mod this a bit so it records the whole screen to make a bug reporter for my app. THen I would use your demo window and just show the Start/stop and maybe the Text area. THen I could make the user send me the video instead of trying to figure it out, but not see the screen.
ReplyDeleteI've never had great success with capturing large areas of the screen. Performance may get to be a concern when you have to deal with that many pixels. Let me know if it works!
ReplyDeleteHey everyone, here's a fresh link to try:
ReplyDeletehttp://www.randelshofer.ch/blog/2011/05/pure-java-screen-recorder/
niec worok
ReplyDelete