Problem with toggling between multiple videos on processing 2.2.1

hi,
so im quite a noob, just clearing that.
im working on a project which involves switching between multiple videos on processing when i press a key. im trying to do some initial testing right now, and trying to get processing to switch between two videos on keypress. the video switches alright, but i cant see it in the applet window! the previous video ( in the paused state continues to stay on top ) . how do i fix this?? please help. find the code below -

    import processing.video.*;

    Movie theMov;
    Movie theMov2;



    void setup() { 
      size(1440, 900);
      theMov = new Movie(this, "sin_city.mp4");
      theMov2 = new Movie(this, "blue_velvet.mp4");

      theMov.stop();  
      theMov2.stop();
    }

    void draw() { 
      background (0);
      image(theMov, 0, 0);
      image(theMov2, 0, 0); 
    } 

    void movieEvent(Movie m) { 
      m.read(); 
    } 

    void keyPressed(){
      if (key == 'p'){

            theMov2.pause();
            background(0);
            theMov.play();

              } else if (key == 'o'){

                       theMov.pause();
                       background(0);
                       theMov2.play();

                     }


}

Answers

  • edited October 2014

    You're always displaying both theMov & theMov2:

    image(theMov, 0, 0);
    image(theMov2, 0, 0);
    

    Since it's just 2 Movie streams, you can declare a boolean variable to determine which 1 is active for image():

    set(0, 0, isToggled? theMov2 : theMov);
    

    But if you've got more, you're gonna need a Movie[] array. Plus a variable to keep track of its current index:

    set(0, 0, movies[idx]);
    
  • ok so ultimately im gonna need to toggle between 4 movies. if its not much trouble could you elaborate on the Movie[] array a little? like how do i call the desired movie to play on keyPress. ( sorry if this is a really silly question :P)

  • edited October 2014 Answer ✓

    Like how do I call the desired Movie to play() on keyPressed().

    Something akin to these lines: ~O)

    // forum.processing.org/two/discussion/7852/
    // problem-with-toggling-between-multiple-videos-on-processing-2-2-1
    
    import processing.video.Movie;
    
    static final int QTY = 4;
    final Movie[] movies = new Movie[QTY];
    int idx;
    
    void keyPressed() {
      int k = keyCode, n = k - '1';
    
      if (n>=0 & n<QTY & n!=idx) {
        movies[idx].pause();
        movies[idx = n].loop();
      }
    }
    

    More about arrays: =:)

  • edited October 2014

    cancelled this comment since it was useless :)

  • o sorry! didnt see your new comment. let me try it out!

  • hell yea!
    it worked! thanks so much GoToLoop!
    so i understand bits of what you have done there, but say i want to use very specific keys, lets say 'a' 's' 'd' to trigger off the videos, then how do i go about doing that?? Some help would be greatly appreciated!

  • edited October 2014 Answer ✓

    ... but say I want to use very specific keys, let's say 'a' 's' 'd' to trigger off the videos, ...

    There are couple of strategies for it. For example, switch/case associating keyCode w/ a returning index: *-:)


    void keyPressed() {
      int k = keyCode, n = getMovieIndex(k);
    
      if (n>=0 & n!=idx) {
        movies[idx].pause();
        movies[idx = n].loop();
      }
    }
    
    static final int getMovieIndex(int k) {
      switch (k) {
      case 'A': 
        return 0;
      case 'S': 
        return 1;
      case 'D': 
        return 2;
      case 'W': 
        return 3;
      default: 
        return -1;
      }
    }
    

    P.S.: getMovieIndex() is only necessary if indices associated to a keyCode is arbitrary.
    If it happens to be in alphabetical order, the same trick from my 1st example can be used. Just replace '1' w/ 'A'!

  • edited October 2014

    yep! it worked! im just having one issue. when i load the java applet, its obviously a blank black screen which is fine. however, when i click on 'a' nothing happens. But when i click on 's' or 'd' for that matter it works, after which if i press 'a' then that also works. Could it be because the system has considered the default movie[idx] as '0', because of which, when i click 'a' for the first time it does nothing? if thats the case, or whatever else the case, whats the work around? im attaching my entire code for you to see in case i have goofed up somewhere. thanks a ton! :)

    import processing.video.Movie;
    
    static final int QTY = 3;
    final Movie[] movies = new Movie[QTY];
    int idx;
    
    
    void setup() { 
      size(1440, 900);
      movies[0] = new Movie(this, "sin_city.mp4");
      movies[1] = new Movie(this, "blue_velvet.mp4");
      movies[2] = new Movie(this, "finale.mp4");
    
      movies[0].stop();  
      movies[1].stop();
      movies[2].stop();
    }
    
    void draw() { 
      background(0);
      set(0,0,movies[idx] ); 
      //image(films[0],0,0);
      //image(films[1],0,0);
      //image(films[2],0,0);
    } 
    
    void movieEvent(Movie m) { 
      m.read(); 
    } 
    
    static final int getMovieIndex(int k) {
      switch (k) {
      case 'A': 
        return 0;
      case 'S': 
        return 1;
      case 'D': 
        return 2;
      default: 
        return -1;
      }
    }
    
    void keyPressed() {
      int k = keyCode, n = getMovieIndex(k) ;
    
      if (n >= 0 & n != idx) {
        movies[idx].pause();
        movies[idx = n].loop();
      }
    }
    
  • edited October 2014

    ok so i just made a small change and it seems to be working perfect now! is this a good way to tackle this? -
    if (n >= 0 ){ //& n!= idx) { movies[idx].pause(); movies[idx = n].loop(); }

  • edited October 2014

    That "bug" happens b/c no Movie plays at the beginning. And since idx = 0, it's wrongly assumed movies[0] is active! My propose is include movies[0].loop() within setup() rather than remove & n!=idx: o=>

    void setup() {
      size(1440, 900, JAVA2D);
      frameRate(30);
      noSmooth();
    
      movies[0] = new Movie(this, "sin_city.mp4");
      movies[1] = new Movie(this, "blue_velvet.mp4");
      movies[2] = new Movie(this, "finale.mp4");
    
      movies[idx].loop();
    }
    

    P.S.: & n!=idx is there to avoid unnecessary pause() & play() for the same active idx. Just a tiny optimization! ;)

  • edited December 2014

    Here's a tweaked version which relies on noLoop()/redraw() combo, so canvas updates only when movieEvent() happens. I expect it to be lighter this way. ~:> Also included pause/rewind/forward features! <:-P

    /**
     * Movie Player (v1.21)
     * by GoToLoop  (2014/Oct/31)
     *
     * forum.processing.org/two/discussion/7852/
     * problem-with-toggling-between-multiple-videos-on-processing-2-2-1
     */
    
    import processing.video.Movie;
    import org.gstreamer.elements.PlayBin2;
    
    static final PlayBin2.ABOUT_TO_FINISH FINISHING = new PlayBin2.ABOUT_TO_FINISH() {
      @ Override void aboutToFinish(PlayBin2 elt) {
        println("Finishing...", elt.get("uri"));
      }
    };
    
    static final String[] FILMS = {
      "sin_city.mp4", 
      "blue_velvet.mp4", 
      "finale.mp4"
    };
    
    static final float JUMP = 3.0, MULT = 3.34, FPS = 30.0;
    
    final Movie[] movies = new Movie[FILMS.length];
    Movie m;
    
    int idx, x, y;
    boolean isPaused;
    
    void setup() {
      size(1280, 800, JAVA2D);
    
      noSmooth();
      noLoop();
      frameRate(FPS);
      background(0);
    
      for (String s : FILMS)  (movies[idx++] = new Movie(this, s))
        .playbin.connect(FINISHING);
    
      (m = movies[idx = 0]).loop();
    
      while (m.width == 0)  delay(100);
      centralizeMovie();
    }
    
    void draw() {
      set(x, y, m);
    
      frame.setTitle(round(m.time()) + "\t " + round(m.duration())
        + "\t " + FILMS[idx]);
    }
    
    void movieEvent(Movie m) {
      m.read();
      redraw();
    }
    
    void keyPressed() {
      int k = keyCode, n = k - '1';
    
      if (n>=0 & n<movies.length & n!=idx) {
        m.pause();
        (m = movies[idx = n]).loop();
        isPaused = false;
    
        centralizeMovie();
        background(0);
        return;
      }
    
      if (k==LEFT | k==RIGHT | k==UP | k==DOWN)
        jumpMovie(m, k==RIGHT | k==UP, k==DOWN | k==UP);
      else mousePressed();
    }
    
    void mousePressed() {
      if (isPaused ^= true)  m.pause();
      else                   m.play();
    }
    
    void centralizeMovie() {
      x = width  - m.width  >> 1;
      y = height - m.height >> 1;
    }
    
    static final void jumpMovie(Movie m, boolean forward, boolean faster) {
      float time = m.time(), len = m.duration();
    
      if (time>1.0 & time<len - JUMP) {
        float where = time + (forward? JUMP : -JUMP)*(faster? MULT : 1.0);
        m.jump(constrain(where, 0.0, len - 1.0));
      }
    }
    
    @ Override void exit() {
      for (Movie m : movies)  m.stop();
      super.exit();
    }
    
  • edited October 2014

    thanks so much GoToLoop! obviously both the codes are working. Ok so let me fill you in on the bigger picture. im doing all of this for a art festival called Story of Light. And one of the exhibits is going to be a television ( well at least we are going to make it seem like a television). there will be different colored stools in front of the TV. when a user comes and sits on lets say, the red chair, the surrounding light is going to change color to a red light & after maybe a 2 second delay the TV will switch on, showing some news videos footage that sort of matches the mood of that particular light color. So when the first user walks in, i need the tv screen to be blank, in which case, 'movies[idx].loop' wont work for me. Any workaround that? Also thanks so much for the pause and forwarding features! really! but wont really be needing them :D

    also any ideas on how im finally gonna be interfacing this video toggling using analog sensors on the arduino?

  • edited October 2014

    also regarding the second code that you sent me, the first time i fire up the applet, the video plays off the centre of the applet, towards the right bottom edge. However after toggling around, when i return to it, it plays in the centre..

  • @GoToLoop Thank you very much!! over the last two weeks I have poured over many forum posts reading over your contributions in an effort to write a small program that interfaces with the kinect and allows me to using the depth image as a mask. I have basically completed it, with a few issues that I can't seem to resolve, but they are minor ...anyway, thanks!

    //
    //            SpoutSender
    //
    //      Send to a Spout receiver
    //
    //           spout.zeal.co
    //
    //       http://spout.zeal.co/download-spout/
    //
    //
    //      Rotating cube by Dave Bollinger
    //      http://processing.org/examples/texturecube.html
    //
    /**
     * Movie Player (v1.21)
     * by GoToLoop  (2014/Oct/31)
     *
     * forum.processing.org/two/discussion/7852/
     * problem-with-toggling-between-multiple-videos-on-processing-2-2-1
     */
    /*
      This sketch shows how you can record different takes.
    
     This can be useful when you have randomized generative
     graphics and you want to save only the "good parts".
    
     For instance, try to record the ball only moving down.
     (press R to start when the ball is high, press R again
     to stop when the ball is low).
    
     Do this multiple times to get a video in which the
     ball only goes down.
     */
    
    import com.hamoid.*;
    import processing.video.Movie;
    import spout.*;
    import org.openkinect.freenect.*;
    import org.openkinect.processing.*;
    import org.gstreamer.elements.PlayBin2;
    import java.io.FilenameFilter;
    
    static final PlayBin2.ABOUT_TO_FINISH FINISHING = new PlayBin2.ABOUT_TO_FINISH() {
      @ Override public void aboutToFinish(PlayBin2 elt) {
      }
    };
    
    //usefull so that we do not overwrite movie files in save directory
    int ye = year();
    int mo = month();
    int da = day();
    int ho = hour();
    int mi = minute(); 
    int se = second();
    //global frames per second
    static final float FPS = 30.0;
    //index
    int idx;
    //string array for films located in data directory
    String[] FILMS;
    //string for weather or not we are exporting to .mp4 using ffmpeg
    String record;
    boolean isPaused;
    boolean recording = false;
    // Depth image
    PImage depthImg;
    // Which pixels do we care about?
    int minDepth =  60;
    int maxDepth = 800;
    //max depth 2048
    
    //declare a kinect object
    Kinect kinect;
    //declare videoExport
    VideoExport videoExport;
    //movie array
    Movie[] movies;
    //movie
    Movie m;
    // DECLARE A SPOUT OBJECT
    Spout spout;
    
    
    void setup() {
      //I have to call resize becasue for some reason P2D does not
      //seem to to actually size to display width/height on first call
      size(displayWidth, displayHeight, P2D);
      surface.setResizable(true);
      surface.setSize(displayWidth, displayHeight);
      surface.setLocation(0, 0);
      noSmooth();
      frameRate(FPS);
      background(0);
    
      kinect = new Kinect(this);
      kinect.initDepth();
    
      // Blank image with alpha channel
      depthImg = new PImage(kinect.width, kinect.height, ARGB);
    
      // CREATE A NEW SPOUT OBJECT
      spout = new Spout(this);
      //CREATE A NAMED SENDER
      spout.createSender("BodyMapper Spout");
    
      println("Press R to toggle recording");
      //.mp4 is created with year month date hour minute and second data so we never save over a video
      videoExport = new VideoExport(this, "savedVideo/Video" + ye + mo + da + ho + mi + se + ".mp4");
    
      videoExport.setFrameRate(15); 
    
      //videoExport.forgetFfmpegPath();
      //videoExport.dontSaveDebugInfo();
    
      java.io.File folder = new java.io.File(dataPath(""));
    
      // this is the filter (returns true if file's extension is .mov or .mp4)
      java.io.FilenameFilter movFilter = new java.io.FilenameFilter() {
        String[] exts = {
          ".mov", ".mp4"
        };
        public boolean accept(File dir, String name) {
          name = name.toLowerCase();
          for (String ext : exts) if (name.endsWith(ext)) return true;
          return false;
        }
      };
      //create an array of strings comprised of .mov/.mp4 in data directory
      FILMS = folder.list(movFilter);
      //using the number of videos in data directory we can create array of videos
      movies = new Movie[FILMS.length];  
    
      for (String s : FILMS)  (movies[idx++] = new Movie(this, s))
        .playbin.connect(FINISHING);
      //start us off by playing the first movie in the array
      (m = movies[idx = 0]).loop();
    }
    
    void draw() {
      // Threshold the depth image    
      int[] rawDepth = kinect.getRawDepth();
      for (int i=0; i < rawDepth.length; i++) {
        if (rawDepth[i] >= minDepth && rawDepth[i] <= maxDepth) {
          //if pixels are in range then turn them to alpha transparency
          depthImg.pixels[i] = color(0, 0);
        } else {
          //otherwise turn them black
          depthImg.pixels[i] = color(0);
        }
      } 
      //update pixels from depth map to reflect change of pixel colour
      depthImg.updatePixels();
      //blur the edges of depth map
      depthImg.filter(BLUR, 1);  
    
    
      //draw movie to size of current display
      image(m, 0, 0, displayWidth, displayHeight);
      //draw depth map mask to size of current display 
      image(depthImg, 0, 0, displayWidth, displayHeight);
      //share image through Spout
      // Sends at the size of the window    
      spout.sendTexture();  
      //if key r is pressed begin export of .mp4 to save directory
      if (recording) {
        videoExport.saveFrame();
      }  
      //TODO - create second window for preferences and instructions
      fill(255);
      text("Recording is " + (recording ? "ON" : "OFF"), 30, 100);
      text("Press r to toggle recording ON/OFF", 30, 60);
      text("Video saved to file after application is closed", 30, 80);
    }
    
    void movieEvent(Movie m) {
      m.read();
    }
    
    void keyPressed() {
      int k = keyCode;
      if (k == RIGHT) {
        // Cycle forwards
        if (idx >= movies.length - 1) {
          idx = 0;
        } else {
          idx += 1;
        }
      } else if (k == LEFT) {
        // Cycle backwards
        if (idx <= 0) {
          idx = movies.length - 1;
        } else {
          idx -= 1;
        }
      } 
    
      if (k == LEFT || k == RIGHT) {
        m.stop();
        (m = movies[idx]).loop();
        isPaused = false;
        background(0);
      }
    
      if (key == 'r' || key == 'R') {
        recording = !recording;
        println("Recording is " + (recording ? "ON" : "OFF"));
      }
    }
    
    @ Override public void exit() {
      for (Movie m : movies)  m.stop();
      super.exit();
    }
    
Sign In or Register to comment.