We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
Page Index Toggle Pages: 1
frame advance code fails to work (Read 1111 times)
frame advance code fails to work
May 9th, 2005, 8:48pm
 
I've put together some code to step through a movie frame by frame. I'm using the old infamous iSPEC movie file for this. However, the playhead jumps back and forth when I try to use it.

I'm trying to apply v3ga's edge detection and some of my code to it but this jumping back and forth lark when you advance through the frames looks really awful. I want to save individual frames from the movie and stitch them together later but it's not happening.

Code:

import processing.video.*;
Movie myMovie;
float frameDuration = 0.04; //how many frames the movie advances
float playhead = 0.0; //current location of the playhead
float oldPlayhead = 0.0;
int targetWidth = 480;
int targetHeight = 270;
int totalFrames;
boolean newFrame = false;

void setup() {
size(targetWidth,targetHeight,P3D);
myMovie = new Movie(this, "test.mov");
myMovie.loop();
myMovie.framerate(2);
println("movie duration:"+myMovie.duration());
totalFrames = int(myMovie.duration() / frameDuration);
println("total frames:"+totalFrames);
println("width:"+myMovie.width+" height"+myMovie.height);
background(255);
}

void draw() {
if (newFrame && oldPlayhead != playhead){
myMovie.pause();
newFrame = false;
image(myMovie,0,0);
oldPlayhead = playhead;
}
}

// Events
// ==================================================
void movieEvent(Movie myMovie) {
myMovie.read();
newFrame = true;
}
void keyPressed(){
switch(key){
case '+':
case '=':
stepforward();
break;
case '-':
case '_':
stepback();
break;
}
}
// playhead
// ==================================================
void stepforward(){
myMovie.play();
playhead = (playhead+frameDuration)%myMovie.duration();
myMovie.jump(playhead);
println(playhead);
}
void stepback(){
myMovie.play();
playhead = playhead-frameDuration;
if (playhead < 0.0){
playhead += myMovie.duration();
}
myMovie.jump(playhead);
println(playhead);
}

Does this code work on other machines? Have I just programmed it wrong or is the Movie object obstinate?
Re: frame advance code fails to work
Reply #1 - Jul 12th, 2006, 5:34am
 
I want to do just this -- step through a quicktime file with the frame advance triggered by an external event (serial in my case, but I'll settle for keys first!)  I came across processing and it looks like an ideal environment for this, but I can't figure out how to do it.  So, I found st33d's code, and indeed, I find that

1) it looks like it should move step-wise through a QT file, and

2) It skips around apparently randomly, as st33d says.

So, what gives  Can I playback in single, successive frames with processing  Has anyone figured this out  I see that st33d has finished his project (which looks very interesting) -- did he (you) find a way to make this code work, or is ther another solution  Or, did he (you) give up  I hate to think so -- it seems like a simple enough thing to do!

I am a neophyte at this, and don't know Java, only a bit of c, php, and javascript.  Any advice would be most appreciated!

I am using processing 0115 beta on mac OSX10.3.9 on a G4 Powerboook.

I won't repeat his code, which is in his original message.

st33d wrote on May 9th, 2005, 8:48pm:
I've put together some code to step through a movie frame by frame. I'm using the old infamous iSPEC movie file for this. However, the playhead jumps back and forth when I try to use it.

... this jumping back and forth lark when you advance through the frames looks really awful. I want to save individual frames from the movie and stitch them together later but it's not happening.

Re: frame advance code fails to work
Reply #2 - Jul 12th, 2006, 3:36pm
 
I gave up.

But when I was in a Processing class and was trying to help a student with his movie project I discovered that myMovie.pause() probably should be renamed myMovie.stopAtThisBitUntilPlayIsCalledAgainAndNothingElseWillWork(). But that's not to say we shouldn't do that. But it's not a pause in the conventional sense. The other way of saying pause that seems to make sense conventionally is myMovie.speed(0).

So, open Processing, goto your menu bar and select: Open > Examples > Library-Video > MoviePlayback

That will give you a movie to read for this demo. Then paste the following code over the existing code. And that should answer your question.
Code:

import processing.video.*;
Movie myMovie;
void setup(){
size(200, 200);
background(0);
myMovie = new Movie(this, "station.mov");
myMovie.loop();
myMovie.speed(0);
}
void movieEvent(Movie myMovie){
myMovie.read();
}
void draw(){
image(myMovie, 0, 0, width, height);
}
void keyPressed(){
myMovie.jump((myMovie.time() + 0.1) % myMovie.duration());
}
Re: frame advance code fails to work
Reply #3 - Jul 12th, 2006, 6:36pm
 
as you can see in the movie library code, there's not a lot to it. it's not been stress tested in any way to see if jumping around works properly and whatnot, but nobody's actually filed bugs on any of its commands either, so this is news to me..

of course, the code is there, and patches to the library would be most appreciated...
Re: frame advance code fails to work
Reply #4 - Jul 12th, 2006, 7:35pm
 
I think I had my trouble back before dev.processing and I was already doing a fairly extensive job of harrassing advanced Processing users. I didn't report it because I changed my work to work around the problem. Movie.speed(0) works just fine really.

Here's the Movie Library source. In case anybody else wants to investigate.

My guess is that it's something to do with pause not reading the frames. Perhaps that's better for performance if you're just stopping the video at that point. If it is then there only needs to be a mention in the documentation about use of pause() vs speed(0).

As Fry will already know, I've reported it as a bug for now - but there is a usable workaround.
Re: frame advance code fails to work
Reply #5 - Jul 12th, 2006, 8:00pm
 
the movie library source is also included with every release of processing, or you should use the topmost item at:

http://dev.processing.org/source/index.cgi/trunk/processing/video/Movie.java

which will be what's currently in development at the moment, in case there have been changes.
Re: frame advance code fails to work
Reply #6 - Jul 12th, 2006, 10:09pm
 
I just wanted to thank st33d for sharing his work-around solution.  I find that it works fine for what I need right now, and am extremely grateful.  As a newbie, I probably would not have thought of setting the speed to 0.

I haven't modified the code much, but did add back in st33d's forward/reverse switch from his original code, which works fine, and used a DVCProHD 720p movie, which also worked fine, but it does take 5 or more seconds for each frame to display.  Not a problem for me right now, but real-speed smooth video to play back is another matter...

Here is the code as it is for me right now; I wonder, is my thinking in the comments correct?  Is there a frame counter that will tell you the frame number that the playhead is at in the clip?  Converting from seconds to frame numbers seems perilous when all you really care about is the discreet frames.  But I'm new to processing, so I don't know.  Is there any way to take seconds out of the loop?
Code:

import processing.video.*;
Movie myMovie;
float frameRate = 29.97;
/************************************************************************
* frameRate is the number of frames per second as a real time duration. *
* the fact that 29.97 is 30 frames per TC "second" is irrelevant - *
* processing only looks at elapsed time, so, alas, the actual frame rate *
* that is specified in the QT header is the one that needs to be used to *
* get an accurate frame count here. *
*************************************************************************/
float advanceLength = 1/frameRate;

void setup(){
size(1280, 720);
background(0);
myMovie = new Movie(this, "timeCodeDVCProHD720p30.mov");
myMovie.loop();
myMovie.speed(0);
}
void movieEvent(Movie myMovie){
myMovie.read();
}
void draw(){
image(myMovie, 0, 0, width, height);
}
void keyPressed(){
switch(key){
case '+':
case '=':
myMovie.jump((myMovie.time() + advanceLength) % myMovie.duration());
break;
case '-':
case '_':
myMovie.jump((myMovie.time() - advanceLength) % myMovie.duration());
break;
}
}
Re: frame advance code fails to work
Reply #7 - Jul 13th, 2006, 11:32am
 
My thought is that you're much better off sticking with the floats, you can make much more accurate adjustments and making an integer expression of it only complicates the code (see mine).

Another thing; modulo (%) doesn't work in reverse. The number you are wrapping and the ceiling of that wrap must be of the same sign (both negative or positive).

So when stepping back you're going to have to say, if(movie.time() - advanceLength < 0){ movie.jump(movie.duration() + movie.time() - advanceLength);

At least I think that's right. But you get the idea anyway.
Re: frame advance code fails to work
Reply #8 - Jul 22nd, 2006, 7:17am
 
I've been playing with this for a while and it seems to work, but I have run into something else that I don't understand.

I seem unable to draw a frame of a quicktime movie from within a control loop.  That is, with myMovie.speed(0),

Code:

image(myMovie, 0, 0, width, height);


works as a one-time command, displaying as a still image whichever frame the playhead is at, but putting it in a loop like this:

Code:

for (int i = 0; i < number; i++) {
println("now printing frame " + (i + 1) + " of " + number + " frames");
myMovie.jump(myMovie.time() + frameLength);
image(myMovie, 0, 0, width, height);
}


produces a new line of text for each would-be frame, but the quicktime image doesn't  update until the 'for' loop is done, and then it jumps 'number' frames in one leap.  This is not what I want; what I want is to display a quicktime frame, then the next, then the next, etc., not at some continuous speed, but one frame at a time.   I've tried inserting various 'delay's and it doesn't help; I've tried letting the 'image' command reside in 'draw' and be triggered by flags, tried putting it in seperate functions, tried making the loop variables global in scope, but I can't get it to work.

Can anyone tell me why it does this, and whether there is a way around it?  I'm about to outsource the control loop to a microprocessor and then have it control 'processing's' display by triggering it one frame per external command, which it can do, but it really seems like it should be able to do this itself, and that I just don't know something (which is hardly new!).

Thanks.
Re: frame advance code fails to work
Reply #9 - Jul 22nd, 2006, 4:04pm
 
The display is updated at the end of the draw() block.
Code:

draw(){
//yadda yadda
}
//update happens here

So ideally you would need to:
Code:

//instead of: for(int i=0;i<10;i++){

int i = 0;
void setup(){}
void draw(){
if (i < 10){
i++;
print("frame " + i);
}
}

for() loops doing a lot of stuff without anyone knowing is one of the joys of programming. So the answer is, "no". To create a slow for() you don't use for().
Page Index Toggle Pages: 1