How to switch between multiple movies?/Play movie after a movie?

edited January 6 in Library Questions

Hello everybody.

I'm new here, so sorry if the question is something easy to solve. I'm working on a project and it doesn't work the way it should. Im selecting an area via a webcam. If something enters the selection (mensaanwezig) it should play a video.

There's playing a video at all times, myMovie 1 (should be looping). When something enters it switches to myMovie 2. When the person leaves/and when the end of myMovie2 has been reached, it should play myMovie3 at full length, regardless if something enters or leaves the area. after myMovie3 happened it should switch back to the start of myMovie 1.

I managed to get myMovie2 to play when somebody enters the area, but it switches back to myMovie 1 immediately when something leaves the area.

Can somebody tell me what i'm missing?

import processing.video.*;

Movie myMovie;
Movie myMovie2;
Movie myMovie3;


int x, y, w=20, h=20 ;
int togglemouse=1;
int H, S, B, Hold, Sold, Bold;
int verschil, threshold=50;
int modeselector=1;
color kleur;
boolean mensaanwezig; 
boolean changed = false;

Capture cam;

void setup() {
  size(640, 480);
  //fullScreen();

  myMovie = new Movie(this, "Movie01B.mp4");
  myMovie2 = new Movie(this, "Movie02B.mp4");
  myMovie3 = new Movie(this, "Movie03B.mp4");

  myMovie.loop();
  myMovie2.loop();
  myMovie3.loop();

  cam = new Capture(this, 640, 480, "Logitech Webcam C930e");
  cam.start();
} 

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

..........................

void projectionmode() {

  if (mensaanwezig ==true) {
    if (changed==false) {
      changed=true;
      myMovie2.jump(0);
    }


    if (myMovie2.time() < /**myMovie2.duration*/ 45) {
      myMovie2.play();
      image(myMovie2, 0, 0);
    } else {
      myMovie3.play();
      image(myMovie3, 0, 0);
      if (myMovie3.time() <= /**myMovie3.duration*/ 45) {
        changed=false;
      }
    }
  } else {
    if (changed==true) {
      changed=false;
    }
    myMovie.play();
    image(myMovie, 0, 0);
  }
}
Tagged:

Answers

  • Answer ✓

    I suggest using states as it should make this business easier to follow. Untested code and it shows the concept.

    Kf

    final int IDLE=0;
    final int PREPFIRST=1;
    final int ACTIVEFIRST=2;
    final int PREPSEC=3;
    final int ACTIVESEC=4;
    final int FINISH=5;
    
    int state=IDLE;
    
    void projectionmode() {
    
      if (mensaanwezig ==true && state==IDLE) 
        state=PREPFIRST;
    
      if (myMovie2.time()<45) 
        state=PREPSEC;
    
      if (myMovie3.time()<45) 
        state=FINISH;
    
      switch(state) {
      case IDLE:
        image(myMovie, 0, 0);
        break;
      case PREPFIRST:
        myMovie2.jump(0);
        state=ACTIVEFIRST;
        break;
      case ACTIVEFIRST:
        image(myMovie2, 0, 0);
        break;
      case PREPSEC:
        myMovie3.jump(0);
        state=ACTIVESEC;
        break;
      case ACTIVESEC:
        image(myMovie3, 0, 0);
        break;
      case FINISH:
        mensaanwezig=false;
        break;
      default:
        break;
      }
    }
    
  • @kfrajer

    Thanks for the quick answer. I was up all night but i couldn't get it to work.

    H=int(hue(kleur)); S=int(saturation(kleur)); B=int(brightness(kleur));

    verschil=abs(Hold-H)+abs( Sold-S)+abs( Bold-B);

    if (verschil>threshold) { mensaanwezig=true; } else { mensaanwezig=false; } }

    What i have now is a boolean that works on if the colour in the selected area changes.

    for the states i would need: A: play myMovie1 (mensaanwezig false) B: play myMovie2 (mensaanwezig true) and C: played every time at full length when mensaanwezig true switches back to false) <- but how do i devine this?

  • Answer ✓

    So I think your main bug in the above code is that you are not testing your times properly as in if (myMovie3.time()<45). It should be larger than. Try the code below. To make it work, you need to set the color threshold to trigger the effect (don't forget to set the movies). To setup the color threshold, find an item that has a very unique color... let's say a color similar to apple green. Then execute the sketch with state set to CALIBRATION. Your video cam should play. Then bring this item to the field of view of the camera. Click on the item and record the color. Stop the sketch and update the Target colors. You might need to adjust COLTHRESH as well. Play the sketch again and verify the color is being detected. After you are happy, stop the sketch, change the state from CALIBRATION to IDLE in setup() and run it. Bring your cue color into the field of view to trigger movie2 followed by movie3 before it returns back to movie1 and ready for a new trigger.

    Kf

    // Processing forum Jan 7/2018
    //Description: Play movies sequentially after a visual cue
    //REFERENCE: https://forum.processing.org/two/discussion/25847/how-to-switch-between-multiple-movies-play-movie-after-a-movie#latest
    //By KF
    
    
    import processing.video.*;
    
    
    
    //Visual cue trigger
    final int TARGETRED=139;
    final int TARGETGRN=190;
    final int TARGETBLU=82;
    
    final int COLTHRESH=40;           //Threshold for visual cue detection
    final color RED=color(255, 0, 0); //New color for pixels matching cue color
    
    final int CALIBRATION=-1;  //Use this state only when calibrating trigger color
    final int IDLE=0;
    final int PREPFIRST=1;
    final int ACTIVEFIRST=2;
    final int PREPSEC=3;
    final int ACTIVESEC=4;
    final int FINISH=5;
    
    int state;
    
    
    Movie myMovie;
    Movie myMovie2;
    Movie myMovie3;
    
    float m1Duration, m2Duration, m3Duration;    
    boolean mensaanwezig; 
    
    Capture cam;
    
    void setup() {
      size(640, 480);
    
      myMovie = new Movie(this, "transit.mov");
      myMovie2 = new Movie(this, "shortrun.mp4");
      myMovie3 = new Movie(this, "video720x480.mp4");
    
      myMovie.loop();
      myMovie2.loop();
      myMovie3.loop();
    
      m1Duration=myMovie.duration()*0.98;
      m2Duration=myMovie2.duration()*0.98;
      m3Duration=myMovie3.duration()*0.98;
    
    
    
      myMovie2.pause();
      myMovie3.pause();
    
      cam = new Capture(this, 640, 480);
      cam.start();
      println(cam.width+" "+cam.height+"\n");
      //println(Capture.list());
      println(m1Duration, m2Duration, m3Duration);
    
    
      // *****************************
      // *****CHOOSE either next******
      // *****************************
      state=CALIBRATION;
      //state=IDLE;
    } 
    
    void captureEvent(Capture c) {
      c.read();
    }
    
    void movieEvent(Movie m) {
      m.read();
    }
    
    
    void draw() {
    
      image(cam, 0, 0);
      loadPixels();
      for (int i=0; i<cam.width; i++) {
        for (int j=0; j<cam.height; j++) {
          int loc=i+j*width;
          int r=(pixels[loc]>>16)&0xff;
          int g=(pixels[loc]>>8)&0xff;
          int b=(pixels[loc]>>0)&0xff;
          if (dist(r, g, b, TARGETRED, TARGETGRN, TARGETBLU)<COLTHRESH) {
            mensaanwezig=true;
            pixels[loc]=RED;
          }
        }
      }
      updatePixels();
    
      if (state==CALIBRATION) {
        if (frameCount%60==0) println("Detected "+(mensaanwezig?"Y":"N"));
    
        if (frameCount%120==0) println("In calibration mode. After setting up color (mouseclicked on \nunique color on video), stop sketch, update TARGET colors \nand set state to IDLE (instead of CALIBRATION)");
        return;
      }
    
    
      background(255, 150, 0);
    
    
      if (mensaanwezig ==true && state==IDLE) 
        state=PREPFIRST;
    
      switch(state) {
      case IDLE:
        image(myMovie, 0, 0);
        break;
      case PREPFIRST:
        myMovie.pause();
        myMovie2.jump(0);
        myMovie2.play();
        state=ACTIVEFIRST;
        break;
      case ACTIVEFIRST:
        image(myMovie2, 0, 0);
        //println(myMovie2.time()+"\t"+(myMovie2.time()>m2Duration));
        if (myMovie2.time()>=m2Duration) 
          state=PREPSEC;
        break;
      case PREPSEC:
        myMovie3.jump(0);
        myMovie2.pause();  //If one uses paly, no need to call pause at the end of movie
        myMovie3.play();
        state=ACTIVESEC;
        break;
      case ACTIVESEC:
        image(myMovie3, 0, 0);
        if (myMovie3.time()>=m3Duration) 
          state=FINISH;
        break;
      case FINISH:
        myMovie3.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break;
      default:
        break;
      }
    }
    
    void mousePressed() {
    
      color m=get(mouseX, mouseY);
      int r=(m>>16)&0xff;
      int g=(m>>8)&0xff;
      int b=(m>>0)&0xff;
      println("************************");
      println("COLOR DETECTED r,g,b =>  ", r, g, b);
      println("************************");
    }
    
  • edited January 9

    @kfrajer thank you very much for your help and direction! You can't imagine how much your help means to me.

    void mouseClicked() { if (togglemouse==1) { x=mouseX; y=mouseY; } else { w=mouseX-x; h=mouseY-y; } togglemouse=togglemouse*-1; }

          void lichtmeten() {
              PImage gemmiddeldekleur = cam.get(int(map(x, 0, width, 0, cam.width)), int(map(y, 0, height, 0, cam.height)), int(map(w, 0, width, 0, cam.width)), int(map(h, 0, height, 0, cam.height))); 
              gemmiddeldekleur.resize(1, 1);
              kleur = gemmiddeldekleur.get(0, 0);
    
    
              H=int(hue(kleur));
              S=int(saturation(kleur));
              B=int(brightness(kleur));
    
              verschil=abs(Hold-H)+abs( Sold-S)+abs( Bold-B); 
    
              if (verschil>threshold) {
                mensaanwezig=true;
              } else {
                mensaanwezig=false;
              }
            }
    

    this is what i did to select the area in the previous code. I added that one instead of yours.

    The code works and I finally got to see myMovie3. But i'm still not there yet. If mensaanwezig=true, myMovie2 starts playing, till the very end.. regardless if the threshold changed. After myMovie2 ends, myMovie3 starts playing till the very end, which is beautiful, because that's what it's supposed to do.

    The idea is that movie2 switches to myMovie3 immediately if someone left the area and/or movie2 is played till it's end.

    Right now it switches from 2 to 3 till the very end, but it's not because someones been in the area for that long, but because it's programmed to play if mensaanwezig=true.

    Can't i make a boolean for if mensaanwezig=true switchtes to mensaanwezig=false?

    I'm sorry if i bother you, and I really appreciate your help!

    liiwn

  • Answer ✓

    Note 1: I will leave FINISH case as it is to ensure mensaanwezig is set to false not matter what.

    To start playing movie3, you will need to modified case ACTIVEFIRST:

      case ACTIVEFIRST:
        image(myMovie2, 0, 0);    
        if (myMovie2.time()>=m2Duration || mensaanwezig==false) 
          state=PREPSEC;
        break;
    

    Keeping your code with your modified suggestion (void lichtmeten() definition), the above modification will stop playing movie2 as soon as the trigger is not present anymore and it will start playing the movie3 immediately.

    Kf

  • @kfrajer THANK YOU SO MUCH! IT WORKS! I want to thank you very much for you help, and I hope I didn't annoy you to much :)

  • Answer ✓

    @liiwn glad to hear it is working. All the best!

    Kf

  • @kfrajer Hey there, it's me again.. , so now i'm trying to make an alternative ending:

    import processing.video.*;
    
    final int CALIBRATION=-1;  //Use this state only when calibrating trigger color
    final int IDLE=0;
    final int PREPFIRST=1;
    final int ACTIVEFIRST=2;
    final int PREPSEC=3;
    final int PREPSECB=4;
    final int ACTIVESEC=5;
    final int ACTIVESECB=6;
    final int FINISH=7;
    final int FINISHB=8;
    
    
    void projectionmode() {
    
     if (mensaanwezig ==true && state==IDLE) 
        state=PREPFIRST;
    
      switch(state) {
      case IDLE:
        image(myMovie, 0, 0);
        break;
      case PREPFIRST:
        myMovie.pause();
        myMovie2.jump(0);
        myMovie2.play();
        state=ACTIVEFIRST;
        break;
      case ACTIVEFIRST:
        image(myMovie2, 0, 0);
        println(myMovie2.time()+"\t"+(myMovie2.time()>m2Duration));
        if (myMovie2.time()>=m2Duration || mensaanwezig==false) 
          state=PREPSEC;
        if (myMovie2.time()>=m2Duration || mensaanwezig==false) 
          state=PREPSECB;
        break;
      case PREPSEC:
        myMovie3.jump(0);
        myMovie2.pause();
        myMovie3.play();
        state=ACTIVESEC;
        break;
      case PREPSECB:
        myMovie4.jump(0);
        myMovie2.pause();
        myMovie4.play();
        state=ACTIVESECB;
        break;
      case ACTIVESEC:
        image(myMovie3, 0, 0);
        if (myMovie3.time()>=m3Duration) 
          state=FINISH;
      case ACTIVESECB:
        image(myMovie4, 0, 0);
        if (myMovie4.time()>=m4Duration) 
          state=FINISHB;
        break;
      case FINISH:
        myMovie3.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break;
      case FINISHB:
        myMovie4.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break;
      default:
        break;
      }
    }
    

    myMovie2 has a duration of 45 secs. Let's say, if mensaanwezig turns out to be false within the first 15 secs while myVideo2 is playing, it switches to myVideo3 (PREPSEC, ACTIVESEC, FINISH). If mensaanwezig=false happens (or if myVideo2 duration has been reached) after those 15 secs, it should play myVideo4(PREPSECB, ACTIVESECB, FINISHB).

    I need a way to select the timing of myMovie2. I thought i could add that in ACTIVEFIRST under it's if statement.

    Eventually i would like to add another ending that happens if mensaanwezig=false happens between 15 & 30.

    If this is possible, could you help me with your wisdom one more time?

    Again, thank you very much! Have a nice weekend.

  • edited January 14

    myMovie 1 (should be looping). When something enters it switches to myMovie 2. When the person leaves/and when the end of myMovie2 has been reached, it should play myMovie3 at full length, regardless if something enters or leaves the area. after myMovie3 happened it should switch back to the start of myMovie 1.

    Keep in mind that if you are planning to extend your logic, it currently looks like this:

    The background movie loops. When an event happens, a sequence of one or more movies plays, then the background restarts.

    ...which is, slightly more abstract:

    Here is a list of movies that lead to other movies.

    ...with looping as a special case handling of bgMovie -> bgMovie.

    One way to approach that in general is a queue like this:

    0: bgMovie, 0 (infinite loop)
    

    ...and when an event happens you add things to the front, like this:

    0: movie2, 45 // now playing
    1: movie3, 15
    2: bgMovie, 0
    

    When a movie finishes playing, you remove it from the queue and start playing the next movie.

    0: movie3, 15  // now playing
    1: bgMovie, 0
    
    0: bgMovie, 0  // now playing
    

    Now you can add really complex behaviors to your movie system easily by just adding / removing queued movies -- you don't have to program a set of special rules for each transition. If events happen to change the remaining duration of a movie, or remove it, or switch what comes next, you can express all those things concisely as operations that edit queue items. Common ones might be:

    • Replace everything in the queue
    • Add things after the current item
    • Remove all items from the queue but the last one

    If you want to add complex behaviors like cross-fading, you don't have to create a cross-fade for every single possible transition -- you can just create one cross-fade behavior that acts on the current and next items in the queue. Et cetera.

  • Answer ✓

    @jeremydouglass Good concept. Maybe one day I'll do a demo. I can envision having a stack of videos and a stack of transitions.

    @liiwn Here is my attempt based on initial concept. Notice I didn't have the chance to test this code. If this code keeps growing at this rate, then I suggest changing the name of the constant fields (aka. states) and the movie's field names so they are related to each other in a more clear way. Also notice I removed FINISHEDB and modified your FINISH case.

    Kf

    void projectionmode() {
    
      if (mensaanwezig ==true && state==IDLE) 
        state=PREPFIRST;
    
      switch(state) {
      case IDLE:
        image(myMovie, 0, 0);
        break;
      case PREPFIRST:
        myMovie.pause();
        myMovie2.jump(0);
        myMovie2.play();
        state=ACTIVEFIRST;
        break;
      case ACTIVEFIRST:
    
      //CONDITIONS:
      //Play movie2 asa mensaanwezig is set to true
      //If mensaanwezig is set to false and movie2's time<15: Play movie 3a
      //else if movie2 ends normally: Play movie 3b
    
        image(myMovie2, 0, 0);
        //println(myMovie2.time()+"\t"+(myMovie2.time()>m2Duration));
        if (mensaanwezig==false && myMovie2.time()<=15 ) 
          state=PREPSEC;
        else if (myMovie2.time()>=m2Duration) 
          state=PREPSECB;
        break;
      case PREPSEC:
        myMovie3.jump(0);
        myMovie2.pause();
        myMovie3.play();
        state=ACTIVESEC;
        break;
      case PREPSECB:
        myMovie4.jump(0);
        myMovie2.pause();
        myMovie4.play();
        state=ACTIVESECB;
        break;
      case ACTIVESEC:
        image(myMovie3, 0, 0);
        if (myMovie3.time()>=m3Duration) 
          state=FINISH;
      case ACTIVESECB:
        image(myMovie4, 0, 0);
        if (myMovie4.time()>=m4Duration) 
          state=FINISH;
        break;
      case FINISH:
        myMovie3.pause();
        myMovie4.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break;
      default:
        break;
      }
    }
    
  • @kfrajer this doesn't work. myMovie plays fine, but when mensaanwezig=true it flickers between myMovie and Mymovie2. It's like is skips every case from PREPSEC upwards.

  • Answer ✓

    It is hard to tell where the problem is as I don't have a running version of your code. You can add print statements in the following cases: PREPSEC, PREPSECB, FINISH and see if those cases are being called. Another problem is that mensaanwezig might be turning false in your program in another part of your code? I am just guessing, although if this were true, then you will be entering movie3... or it should based on the code above.

    Kf

  • @kfrajer

    I did it! I set specifik time values and a LOT of cases. I also noticed that processing needs some time to load the video files. A few time restarting and it works like it should.

    Thank you for all your help and patience! have a nice day!

    void projectionmode() {

     if (mensaanwezig ==true && state==IDLE) 
        state=PREPFIRST;
    
      switch(state) {
      case IDLE:
        image(myMovie, 0, 0);
        break;
    
      case PREPFIRST:
        myMovie.pause();
        myMovie2.jump(0);
        myMovie2.play();
        state=ACTIVEFIRST;
        break;
    
      case ACTIVEFIRST:
        image(myMovie2, 0, 0);
        println(myMovie2.time()+"\t"+(myMovie2.time()>m2Duration));
        if (myMovie2.time()>=0 && myMovie2.time()<=4 && mensaanwezig==false) //1min
          state=PREPSECA;
          println("t/m 1");
        if (myMovie2.time()>4 && myMovie2.time()<=8 && mensaanwezig==false) //3min
          state=PREPSECB;
          println("t/m 3");
        if (myMovie2.time()> 8 && myMovie2.time()<=12 && mensaanwezig==false) //5min
          state=PREPSECC;
          println("t/m 5");
        if (myMovie2.time()>12 && myMovie2.time()<=16 && mensaanwezig==false) //8min
          state=PREPSECD;
          println("t/m 8");
        if (myMovie2.time()>16 && mensaanwezig==false) //10min
          state=PREPSECE;
          println("t/m 10");
        break;
    
      case PREPSECA:
        myMovie3A.jump(0);
        myMovie2.pause();  
        myMovie3A.play();
        state=ACTIVESECA;
        break;
    
      case PREPSECB:
        myMovie3B.jump(0);
        myMovie2.pause();  
        myMovie3B.play();
        state=ACTIVESECB;
        break;
    
      case PREPSECC:
        myMovie3C.jump(0);
        myMovie2.pause();  
        myMovie3C.play();
        state=ACTIVESECC;
        break;
    
      case PREPSECD:
        myMovie3D.jump(0);
        myMovie2.pause();  
        myMovie3D.play();
        state=ACTIVESECD;
        break;
    
      case PREPSECE:
        myMovie3E.jump(0);
        myMovie2.pause();  
        myMovie3E.play();
        state=ACTIVESECE;
        break;    
    
      case ACTIVESECA:
        image(myMovie3A, 0, 0);
        if (myMovie3A.time()>=m3ADuration) 
          state=FINISHA;
        break;
    
      case ACTIVESECB:
        image(myMovie3B, 0, 0);
        if (myMovie3B.time()>=m3BDuration) 
          state=FINISHB;
        break;
    
       case ACTIVESECC:
        image(myMovie3C, 0, 0);
        if (myMovie3C.time()>=m3CDuration) 
          state=FINISHC;
        break;
    
       case ACTIVESECD:
        image(myMovie3D, 0, 0);
        if (myMovie3D.time()>=m3DDuration) 
          state=FINISHD;
        break;
    
       case ACTIVESECE:
        image(myMovie3E, 0, 0);
        if (myMovie3E.time()>=m3EDuration) 
          state=FINISHE;
        break;
    
      case FINISHA:
        myMovie3A.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break;
    
      case FINISHB:
        myMovie3B.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break; 
    
      case FINISHC:
        myMovie3C.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break;
    
      case FINISHD:
        myMovie3D.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break;
    
      case FINISHE:
        myMovie3E.pause();
        mensaanwezig=false;
        myMovie.loop();
        state=IDLE;  //Back to first movie
        break;
    
      default:
        break;
      }
    }
    
Sign In or Register to comment.