Hi guys,
Have been playing around with reverse video playback and looping.
Found the following notes:
- check that video is actually available and playing before calling mov.jump()
- avoid setting speed = 0.0 (gstreamer error)
- before calling mov.jump() set speed to positive value, after .jump() restore speed
- skip some frames before calling mov.speed() again. otherwise gstreamer errors pop up and framerate drops.
At least these steps worked for me as a workaround with Processing Video library Release 3.
Working example attached (add the default launch2.mp4 to the sketch when testing, H.264 MP4).
Best,
Arne.
/**
* Reverse playback example.
*
* The Movie.speed() method allows to change the playback speed.
* Use negative values for backwards playback. Note that not all
* video formats support backwards playback. This depends on the
* underlying gstreamer plugins used by gsvideo. For example, the
* theora codec does support backward playback, but not so the H264
* codec, at least in its current version.
*
*/
/**
* Working with Processing-Video Release 3
* https://github.com/processing/processing-video/releases/tag/r3-v2.0-beta1
* Note: download from github and put in libraries folder, replacing manager version
*/
import processing.video.*;
Movie mov;
float speed = 1.0;
float pSpeed = speed;
boolean bReady = false;
boolean bReverse = false;
int countdownMax = 10; //--num frames before allowing speed change
int countdownSpeed = countdownMax;
void setup() {
size(560, 406);
background(0);
mov = new Movie(this, "launch2.mp4");
mov.play();
mov.loop();
}
void draw() {
updateMovie();
image(mov, 0, 0, width, height);
fill(0);
text(speed, 10, 20);
text(mov.time(), 10, 40);
text("bReverse: " + (bReverse ? "true" : "false"), 10, 60);
text("countdownSpeed: " + countdownSpeed, 10, 80);
text("fps: " + Math.round(frameRate), 10, 100);
}
void keyPressed() {
//--test jump
mov.speed(0.1); //NOTE: essential to set speed to 1.0 before jump
mov.jump(mov.duration()/2);
mov.speed(speed);
//mov.play(); //--not required?
}
void updateMovie() {
if (mov.available()) {
//--read next frame
mov.read();
//--when movie ready at init jump to middle of video
if(!bReady) {
bReady=true;
mov.jump(mov.duration() / 2.0);
//mov.play(); //not required?
}
//--loop video to end when reaching begin
if(bReady && bReverse && mov.time() <= 0.5) { //--0.5 sec as save value at high speeds
mov.speed(0.1); //NOTE: essential to set speed to positive before jump
mov.jump(mov.duration()); //--jump to end
mov.speed(speed); //--reset to input speed
//mov.play(); //not required?
}
//--update counter for speed change allowance
if(countdownSpeed > 0) {
countdownSpeed--;
}
}
//--map input to speed level
speed = map(mouseX, 0, width, -10, 10);
speed = Math.round(speed * 10.0) / 10.0; //--round number to 2 decimals
//--check for reverse speed
if(speed < 0.0) {
bReverse = true;
} else {
bReverse = false;
}
//--avoid speed 0
if(speed > -0.5 && speed < 0.5) {
if(bReverse) {
speed = -0.5;
} else {
speed = 0.5;
}
}
//--check for allowing speed change
if(speed != pSpeed && countdownSpeed == 0) {
println("change speed");
countdownSpeed = countdownMax;
mov.speed(speed);
//mov.play(); //not required?
}
pSpeed = speed; //--update counter
}