prepare a second video to play without slowing down the first video

Hi, I have a problem with videos launches : I want to play a succession of clips, of 20-30s , in two Movies instances

all together.

clip A1   clip B1
clip A2     ""
 ""        clip B2
etc...

When a new clip begins with play(), B2 by exemple, then A2 which is not finished freezes. I tried with a timer and I saw that in the case where I had to launch the play() the duration of draw() was 200ms vs 4-5ms without play().

I read some discussions with my problem and the only answer is to write the play() in the setup(). But it's not the way I have to use because my project is to play with many clips (more than 500) automatically during

several hours. It's look like to me this is impossible to launch so many clips in the programm start.

Is there a possibility to prepare the new clip to be played without slowing down the draw duration? in a different buffer? something like if (myMovie.available()) {myMovie.play()} does not work... Or is this impossible to work simultaneously with two clips with processing?

I join my sketch with two Movies instances : on the top the clip A serie and clip B serie bottom the two clips series succeed one another with alpha. Please I hope you understand my english.

import processing.video.*;
int nbVideo,numVideo;
boolean choixA,transit;
float mAlpha=0;
Movie  movA,movB,movActif;


void setup() {
  size(1040, 860,JAVA2D);
  noSmooth();
  background(0);
  nbVideo=6;
  numVideo=int(random(1, 6));
  movA=new Movie(this, numVideo+".avi");
  choixA=false;
  transition();
  charge();
}   


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


void charge() {
  int m = millis();
  numVideo =int (random(1, 6));

 if (choixA==true){
  movA=new Movie(this, numVideo+".avi");
  }
 else{
   movB=new Movie(this, numVideo+".avi");
  }
 choixA =!choixA;
 int m2 = millis();
 println(m2-m+"    =charge");   
}


void transition(){
  int m = millis();
  if (choixA==true){
    movB.play();
  }
  else{
   movA.play();
  }
 int m2 = millis();
 println(m2-m +"  =trans");
}



void draw() {
  int m = millis();
  tint (255,100);
  image(movA, 0, 0 );
  image(movB, 500, 0 );
 if (choixA==true){
   movActif=movA;
    }
 else{
   movActif=movB;
    }
 tint (255,100-mAlpha);
 image(movA,0,400);
 tint (255,mAlpha);
 image(movB, 0, 400 );
  if (movActif.time()>=movActif.duration()-5) {
    if (!transit){
      transition();
     transit=!transit;
    }
    if (choixA==true){
      mAlpha+=1;
    }
    else{
      mAlpha-=1;
    }
  if ((mAlpha==100)||(mAlpha==0)){
    charge();
    transit=!transit;
    }
 }

   int m2 = millis();
   if (m2-m>40) {println(m2-m +"   draw");}

}

Answers

  • Don't try to format code with quote! See How to format code and text

  • edited November 2014

    Ended up coding my own solution based on "Movie Player" @ http://forum.processing.org/two/discussion/7852/problem-with-toggling-between-multiple-videos-on-processing-2-2-1.
    However, it's not been tested yet and might be bugged. Hoping you check it out for yourself: ^#(^

    /**
     * Preloaded Clips (v1.3)
     * by GoToLoop (2014/Nov/13)
     *
     * forum.processing.org/two/discussion/8109/
     * prepare-a-second-video-to-play-
     * without-slowing-down-the-first-video
     */
    
    import processing.video.Movie;
    import org.gstreamer.elements.PlayBin2;
    
    final PlayBin2.ABOUT_TO_FINISH finishing =
    new PlayBin2.ABOUT_TO_FINISH() {
      @ Override void aboutToFinish(PlayBin2 elt) {
        preloadRandomClip(int(elt.get("name").toString()));
        println("Finishing...", elt.get("uri"));
      }
    };
    
    static final String EXT = ".avi";
    static final int FPS = 30, MARGIN = 8, PAUSE = 250;
    static final int NUM = 2, QTY = 5, A = 0, B = 1;
    
    final Movie[] clips = new Movie[NUM], loads = new Movie[NUM];
    final int[] x = new int[NUM], y = new int[NUM];
    
    void setup() {
      size(1024, 860, JAVA2D);
    
      noSmooth();
      noLoop();
      frameRate(FPS);
      clear();
    
      (clips[A] = loadRandomClip(A)).play();
      (clips[B] = loadRandomClip(B)).play();
    
      delay(PAUSE);
      centralizeClip(A);
      centralizeClip(B);
    }
    
    void draw() {
      set(x[A], y[A], choosePreloadedClipIfStopped(A));
      set(x[B], y[B], choosePreloadedClipIfStopped(B));
    }
    
    void movieEvent(Movie m) {
      m.read();
      redraw();
    }
    
    Movie choosePreloadedClipIfStopped(int idx) {
      if (loads[idx] != null && !clips[idx].playbin.isPlaying()) { // BUGGED!
        if (clips[idx] == loads[idx])  clips[idx].play();
        else {
          clips[idx].dispose();
          (clips[idx] = loads[idx]).play();
          centralizeClip(idx);
          clear();
        }
    
        loads[idx] = null;
      }
    
      return clips[idx];
    }
    
    Movie preloadRandomClip(int idx) {
      return loads[idx] == null
        ? loads[idx] = loadRandomClip(idx) : loads[idx];
    }
    
    Movie loadRandomClip(int idx) {
      Movie m = new Movie(this, (int)random(QTY) + 1 + EXT);
      m.playbin.set("name", idx);
      m.playbin.connect(finishing);
      return m;
    }
    
    Movie centralizeClip(int idx) {
      Movie m = clips[idx];
      x[idx] = idx == A? MARGIN : width - m.width - MARGIN;
      y[idx] = height - m.height >> 1;
      return m;
    }
    
  • Thank you for your help, but sorry, it didn't work. It stopped after the two first clips, there's no preload and I'm not able to understand ...

  • edited November 2014
    • As said I didn't test it! I'll look forward to do it other time.
    • And it is supposed to preload when the active 1 is about to finish.
    • If you don't understand some of of part of the code, just ask about it.
  • It seems that :

    m.playbin.connect(finishing);

    would make run the :

    final PlayBin2.ABOUT_TO_FINISH finishing = new PlayBin2.ABOUT_TO_FINISH() { @ Override void aboutToFinish(PlayBin2 elt) { // what's "@ Override"? println("Finishing...", elt.get("uri")); //nothing to read on the board... preloadRandomClip(int(elt.get("name").toString())); } };

    when the active 1 (or 2) is about to finish.

    As I don't understand the syntax in the

    Movie preloadRandomClip(int idx) { return loads[idx] == null ? loads[idx] = loadRandomClip(idx) : loads[idx]; // "?" ?? }
    I can't know if there are the instructions in the " preload" which must be modified or a problem in the "aboutToFinish".

  • edited November 2014

    @chrjos, finally I've taken the time to grab some 5 small cat videos from YouTube and placed in the "/data/" folder to check my sketch out! #:-S

    And then found out what was wrong: clips[idx].playbin.isPlaying() was forever true! @-)
    I've ingenuously assumed once a Movie had finished, its isPlaying() would return false! =;

    Class Movie got lotsa boolean fields, including playing, paused, repeat. However they're all protected and we can't access them! And by incomprehensible negligence, there ain't any accessor methods provided for them! X(

    At least field playbin was made public, allowing us to access Movie's internal "gstreamer" library!
    However, I had to peruse that behemoth complicated library in order to learn how to control the Movie!
    All of that b/c Movie developers provided such a poor API for us! ~X(

    PlayBin2.ABOUT_TO_FINISH was 1 of the complicated things I've found out. This time it's Bus.EOS.
    Bus.EOS is called back when the stream is finished playing. So now we can change Movie to another 1! \m/

    If you want to, you can learn more about "gstreamer-java" too: O:-)
    https://gstreamer-java.googlecode.com/svn/trunk/javadoc/1.5/index.html

    And w/o further ado, Preloaded Clips 2: :bz

    /**
     * Preloaded Clips (v2.05)
     * by GoToLoop (2014/Nov/17)
     *
     * forum.processing.org/two/discussion/8109/
     * prepare-a-second-video-to-play-
     * without-slowing-down-the-first-video
     */
    
    import processing.video.Movie;
    
    import org.gstreamer.elements.PlayBin2;
    import org.gstreamer.Bus;
    import org.gstreamer.GstObject;
    
    final PlayBin2.ABOUT_TO_FINISH finishing =
    new PlayBin2.ABOUT_TO_FINISH() {
      @ Override void aboutToFinish(PlayBin2 elt) {
        preloadRandomClip(int(elt.get("name").toString()));
        println("Finishing...", elt.get("uri"));
      }
    };
    
    final Bus.EOS finished = new Bus.EOS() {
      @ Override void endOfStream(GstObject elt) {
        transferLoadedToActive(int(elt.get("name").toString()));
      }
    };
    
    static final String EXT = ".mp4";
    static final int FPS = 30, MARGIN = 8, PAUSE = 250;
    static final int NUM = 2, QTY = 5, A = 0, B = 1;
    
    final Movie[] clips = new Movie[NUM], loads = new Movie[NUM];
    final int[] x = new int[NUM], y = new int[NUM];
    
    boolean isPlaying;
    
    void setup() {
      size(1280, 800, JAVA2D);
    
      noSmooth();
      noLoop();
      frameRate(FPS);
    
      initializeClip(A);
      initializeClip(B);
    }
    
    void draw() {
      set(x[A], y[A], clips[A]);
      set(x[B], y[B], clips[B]);
    }
    
    void keyTyped() {
      if (isPlaying ^= true) {
        clips[A].play();
        clips[B].play();
      } else {
        clips[A].pause();
        clips[B].pause();
      }
    }
    
    void mousePressed() {
      keyTyped();
    }
    
    void movieEvent(Movie m) {
      m.read();
      redraw();
    }
    
    static final int toIdx(int id) {
      return (short) id;
    }
    
    static final int toNum(int id) {
      return id>>>020;
    }
    
    Movie loadClip(int id, String name) {
      Movie m = new Movie(this, name);
      m.playbin.set("name", id);
      m.playbin.connect(finishing);
      m.playbin.getBus().connect(finished);
      println(m.filename, "for index", toIdx(id), "loaded!");
      return m;
    }
    
    Movie loadRandomClip(int id) {
      int rnd, num = QTY>1? toNum(id) : -1;
      while  (num == (rnd = (int)random(QTY) + 1));
      return loadClip(toIdx(id) | rnd<<020, rnd + EXT);
    }
    
    void initializeClip(int id) {
      (clips[toIdx(id)] = loadRandomClip(id)).play();
      isPlaying = true;
      delay(PAUSE);
      centralizeClip(id);
      clear();
    }
    
    void preloadRandomClip(int id) {
      int idx = toIdx(id);
      if (loads[idx] == null)  loads[idx] = loadRandomClip(id);
    }
    
    void transferLoadedToActive(int id) {
      preloadRandomClip(id);
    
      int idx = toIdx(id);
      Movie m = clips[idx], v = loads[idx];
    
      if (m == v)  m.play();
      else {
        (clips[idx] = v).play();
        centralizeClip(idx);
        clear();
        m.dispose();
      }
    
      loads[idx] = null;
      isPlaying  = true;
    
      println("Starting... ", clips[idx].filename);
    }
    
    Movie centralizeClip(int id) {
      int idx = toIdx(id);
      Movie m = clips[idx];
      x[idx] = idx == A? MARGIN : width - m.width - MARGIN;
      y[idx] = height - m.height >> 1;
      return m;
    }
    
  • edited November 2014

    After some thought, I've come to realize that PlayBin2.ABOUT_TO_FINISH w/ its aboutToFinish() method isn't necessary anymore after we've got Bus.EOS and its endOfStream() method! :@)
    So I've refactored version 2 in order to get a more refined & compact version 3: :-bd

    /**
     * Preloaded Clips (v3.13)
     * by GoToLoop (2014/Nov/18)
     *
     * forum.processing.org/two/discussion/8109/
     * prepare-a-second-video-to-play-
     * without-slowing-down-the-first-video
     */
    
    import processing.video.Movie;
    
    import org.gstreamer.Bus.EOS;
    import org.gstreamer.GstObject;
    
    final EOS finished = new EOS() {
      @ Override void endOfStream(GstObject gst) {
        transferLoadedToActive(int(gst.get("name").toString()));
      }
    };
    
    static final String EXT = ".mp4";
    static final int FPS = 30, MARGIN = 8, PAUSE = 1000/FPS;
    static final int NUM = 2, QTY = 5, A = 0, B = 1;
    
    final Movie[] clips = new Movie[NUM], loads = new Movie[NUM];
    final int[] x = new int[NUM], y = new int[NUM];
    
    boolean isPlaying = true;
    
    void setup() {
      size(1280, 800, JAVA2D);
    
      noSmooth();
      noLoop();
      frameRate(FPS);
    
      transferLoadedToActive(A);
      transferLoadedToActive(B);
    }
    
    void draw() {
      set(x[A], y[A], clips[A]);
      set(x[B], y[B], clips[B]);
    }
    
    void keyTyped() {
      if (isPlaying ^= true) {
        clips[A].play();
        clips[B].play();
      } else {
        clips[A].pause();
        clips[B].pause();
      }
    }
    
    void mousePressed() {
      keyTyped();
    }
    
    void movieEvent(Movie m) {
      m.read();
      redraw();
    }
    
    static final int toIdx(int id) {
      return (short) id;
    }
    
    static final int toNum(int id) {
      return id>>>020;
    }
    
    Movie loadClip(int id, String name) {
      Movie m = new Movie(this, name);
      m.playbin.set("name", id);
      m.playbin.getBus().connect(finished);
      println(name, "loaded  for index", toIdx(id));
      return m;
    }
    
    Movie preloadRandomClip(int id) {
      int rnd, idx = toIdx(id), num = QTY>1? toNum(id) : -1;
      while  (num == (rnd = (int)random(QTY) + 1));
      return loads[idx] = loadClip(idx | rnd<<020, rnd + EXT);
    }
    
    Movie transferLoadedToActive(int id) {
      int idx = toIdx(id);
      if (loads[idx] == null)  preloadRandomClip(id);
    
      Movie old = clips[idx], now = clips[idx] = loads[idx];
      if (isPlaying)    now.play();
      if (old == null)  while (now.width == 0)  delay(PAUSE);
    
      centralizeClip(idx);
      println(now.filename, "started for index", idx);
    
      id = int(now.playbin.get("name").toString());
      preloadRandomClip(id);
    
      if (old != null)  old.dispose();
      return now;
    }
    
    Movie centralizeClip(int id) {
      int idx = toIdx(id);
      Movie m = clips[idx];
      x[idx] = idx == A? MARGIN : width - m.width - MARGIN;
      y[idx] = height - m.height >> 1;
      clear();
      return m;
    }
    
Sign In or Register to comment.