threaded video player

after a bit of poking around it looks like the GStreamer code for this addon must be for Linux, but not for 007.
I’m going to take a quick stab at getting it running on 0062, and if that doesn’t work, I’ll let it go and give up.

On the upside, I got the app doing what I need in QuickTime (seamlessly crossfading between a folder of videos), but not with the HD perfomance I need. still, it’s progress…

@Drosen

Yep all the gstreamer code in goVideoPlayer is 0062 :frowning: In fact the whole thing is 0062 with a nasty hack to make it work in 007. Haven’t had time to do a proper update. Sorry about that.

Also I only tested this on Mac and Windows using Quicktime.

I got the app doing what I need in QuickTime (seamlessly crossfading between a folder of videos), but not with the HD perfomance I need

You probably already did this but worth checking: when you load ‘a folder of videos’ do you make sure to call setPause(true) on all of them except the ones you are actually drawing to screen? If not they will be chewing up system resources even if you’re not calling update and draw once they’re loaded. This exact thing bit me once, so thought it was worth mentioning.

I’m only using two GoThreadedVideo objects, one for the current clip, and one for the next clip in line, so I think I’m safe for that. It’s more that the standard quick-time library is getting long in the tooth and just doesn’t perform how I need at a base level. On mac I’ve been using the ofxQtkit video player, which has the performance, but isn’t threaded. I’m hoping that someday in the near future (OF008 maybe?) we can move to a better-performing library as standard across all platforms. Seeing how good GSVideo for Processing is has convinced me that it’s time for a change.

Hi,
Thanks for this great addon gameover! I am using many goThreadedVideo players to load videos in background.
Another quick solution to control the goVideoPlayer::loadMovie calls is to use a static mutex in the treaded function and comment the loading condition in goThreadedVideo::loadMovie.

  
  
static ofMutex LoadMutex;  
//...  
void goThreadedVideo::threadedFunction() {  
  
	// this is where we load the video in a thread  
	// whilst the texture is turned off...  
  
	LoadMutex.lock();  
  
	stopThread();										// immediately stop the thread  
  
	bool ok = video[cueVideo]->loadMovie(name[cueVideo], true);	// load the movie  
	if (ok) {  
		video[cueVideo]->play();							// and start playing it  
		video[cueVideo]->setLoopState(OF_LOOP_NORMAL);  
		loaded[cueVideo] = true;							// set flag that the video is loaded  
	} else {  
		int err = GO_TV_MOVIE_ERROR;  
		ofNotifyEvent(error, err);  
	}  
	  
	LoadMutex.unlock();  
}  
  

i have problems with setLoopState.
no matter what i set it to it always does the normal loop

no -> OF_LOOP_PALINDROME
no -> OF_LOOP_NONE

i tried OF007 and OF 062 on osX
with the normal ofVideoPlayer it works fine.
s.

Although this might be a little off topic, but it was mentioned before: I’m trying to get goThreadedVideo under Linux and OF 007 to work. Instead of updating the goVideoPlayer class to the new gStreamer Code in OF007, I am just changing the goThreadedVideo class so that it is using the standard ofVideoPlayer.

This is done mainly by doing this:

  • Changed the video array in goThreadedVideo.h back to a ofVideoPlayer reference.

  • In goThreadedVideo.cpp removed all the occurances of forceTextureUpload() and added the code directly (which is not very beautiful) in the update and pseudoupdate Function.

That’s the code to switch texturing back on:

  
  
ofTexture & tref = video[cueVideo]->getTextureReference();  
tref.allocate(video[cueVideo]->getWidth(),video[cueVideo]->getHeight(), GL_RGB);  
  

For me, this solution runs perfectly.

Best,
Urs

Update: running ubuntu Oneiric Ocelot…

@hofer: oh cool! so it’s working with of007 that easily? There are a bunch of other changes made to goVideoPlayer for various reasons in the past (which I’d have to hunt down and implement for of007), but great to see this working!

@stephanschulz: I think the problem you’re having is one of precedence. You need to call setLoopState *after* the video has loaded…ie., by watching for a loaded event and then setting the loop state. Does that make sense? Would probably be better if I had some kind of cached value for this…will get to it soon…

Hi Matt.

i am calling setLoopState after loading. I am doing all this in setup()

movie[movieFileCount].loadMovie(fileNameMov); movie[movieFileCount].setLoopState(OF\_LOOP\_PALINDROME);

but it is not looping properly.
i am also noticing that when I am changing the speed once in a while the video freezes for a moment.

s.

@stephanschulz: the reason that is not working is because the video is not actually loaded straight away (that’s the nature of loading on a thread) instead it loads ‘at some point’ on a thread, which is caught in the update and method and then the texture is ‘forced’ to upload and THEN it’s loaded. At that point an event is fired to let you know it’s loaded…otherwise it’s pure guesswork as to when it’s ready…

In the process of adding an example to the repo that demonstrates this I fixed the problem people are facing by caching the the call to setLoopState if the video is not loaded and then applying it once it is actually loaded…

…so although before it wouldn’t work for the reason above…now it should :wink:

You’ll have to check out or pull the new version from the repo…

m

thanks a lot.

Oh and a good hack for pausing/unpausing a movie without getting a ‘pause’ is to just not update that movie instead of calling setPaused(bool b)…

I’ve looked into this a *LOT* and it’s actually the call to setMovieRate() (which is how pause is being done) that causes the glitch/‘pause’ when unpausing -> apparently that call blocks the main thread for a millisec or so…

I’ve found that just not updating works much better and gives that instant, pause/unpause effect. I was going to add it to goVideoPlayer, but felt a bit weird about it -> I’ve used this quite successfully with upto 12 movies playing/pausing, but I think it uses more resources than actually setting the MovieRate to 0…I’d have to do more testing before I was sure…

In the meantime it works by either tracking your own pause var and not updating those movies or you could go ahead and hack it into goVideoPlayer…

M

@gameover

hi i looked at your github.

ofThreadedVideo does not have an example. and unfortunately i am not sure how to combine goVideoPLayer with ofThreadedVideo.

aslo you mention that

At that point an event is fired to let you know it’s loaded

but how do i check for this event?

thx s.

You need to download both goVideoPlayer https://github.com/gameoverhack/goVideoPlayer
AND goThreadedVideo https://github.com/gameoverhack/goThreadedVideo

The example comes with goThreadedVideo

Put the folders called ‘goVideoPlayer’ and ‘goThreadedVideo’ into your addons folder

Copy the ‘example’ folder (inside the goThreadedVideo folder) into your development folder (ie., at the same folder depth as the OF ‘examples’ folder)…

One of the examples shows you how to do events

Should all link up for you.

If you’re starting from scratch simply drag the two folders into a new Xcode OF example project…should just work…if not add the two folders to your search path…

Hope that helps

thanks for the detailed description.
i guess i will have to take a second look at this. because i usually do exactly what you have been describing when i download new addons. but i was not able to find the src folder in your goThreadedVideo example-folder. That’s the folder that usually has the testApp.cpp, testApp.h and main.cpp.
But maybe I missed something.

I will give it a try in the morning.

s.

oh yeah of course! To make it easier to include multiple different examples I’ve started putting different src-SomeExample folders in the ‘examle’ folder -> that way I don’t have to maintain lots of different Xcode/CB/VS2010 prject files as well as different src folders.

Just rename either the ‘src-LoadEvents’ or ‘src-SimpleLoad’ folders to ‘src’…

Time to add a readme :wink:

thanks for updating your github and adding the two example folders.
examples work now.

now that i started working with this a few questions come up:

i have 2000 low res videos each just a few seconds long.

only one video at a time is playing. upon a certain trigger we switch to a new video.
so i thought it would be good to load 5 videos in to memory.

once one video is done playing, we display the next video in the array and load a new video in to the place of the video that just finished playing.

this way i thought there would be no delay when switching between videos. (they will be read of a DVD, which makes things super slow)

i tried to do this with the code below but get an error:

OF: OF_VERBOSE: Load BLOCKED by already thread loading…attempting to enqueue
OF: OF_VERBOSE: Error loading video with error code: 1

Is it even possible to have multiple threaded videos stored in an array?

thanks.

  
  
//--------------------------------------------------------------  
void testApp::setup(){  
  
    ofSetLogLevel(OF_LOG_VERBOSE);  
      
	for(int i = 0; i<maxMovie; i++){  
		video[i].setup();  
	}  
	  
    dir.allowExt("mov");  
	numberOfMovies = dir.listDir(ofToDataPath("videos"));  
	count = 0;  
	//cout<<"count "<<count<<endl;  
  
	currentMovie = 0;  
	//playMovie = 0;  
	loadNextVideo();  
	  
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
  
    ofSetLogLevel(OF_LOG_VERBOSE);  
      
    ofBackground(0,0,0);  
	//if(ofGetFrameNum() % 50 == 0) loadNextVideo(); // load a video every 150 frames  
  
	video[playMovie].update();  
	//video[currentMovie].update();  
}  
  
//--------------------------------------------------------------  
void testApp::loadNextVideo() {  
  
	cout<<"currentMovie "<<currentMovie<<endl;  
    video[currentMovie].loadMovie(dir.getPath(count));  
    video[currentMovie].setLoopState(OF_LOOP_PALINDROME); // Should work here now too  
	  
    // add listeners to the threaded video  
    ofAddListener(video[currentMovie].success, this, &testApp::loaded); // this fires when the video is ACTUALLY loaded and ready  
    ofAddListener(video[currentMovie].error, this, &testApp::error); // this fires if there's a problem loading  
}  
  
//--------------------------------------------------------------  
void testApp::loaded(string & path){  
    ofLogVerbose() << "Video is actually loaded:" << path;  
    //video.setLoopState(OF_LOOP_PALINDROME); // used to only work here  
      
	video[currentMovie].setLoopState(OF_LOOP_PALINDROME);  
	  
    // remember to remove the listeners  
    ofRemoveListener(video[currentMovie].success, this, &testApp::loaded);  
    ofRemoveListener(video[currentMovie].error, this, &testApp::error);  
	  
	playMovie = currentMovie;  
 	currentMovie++;  
	if(currentMovie >= maxMovie) currentMovie = 0;  
	cout<<"new currentMovie "<<currentMovie<<endl;  
	  
	count++;  
	if(count >= numberOfMovies) count = 0;  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	  
    ofSetColor(255,255,255);  
    video[playMovie].draw(0,0);  
}  

ok i think i figured it out.

i saw your post from oct 28th
http://forum.openframeworks.cc/t/threaded-video-player/1335/35

which almost does what i tried to do.
i first got the same BLOCKED error but i added a .close() before loading a new movie.
this solved the error.

Out with the old, in with the new!

I’ve made a new threaded video addon - it solves quite few issues peeps have had with goThreadedVideo/goVideoPlayer.

I’ll be leaving the old addons on my repo, but will not be developing it any more.

You can find out more about the new one here: http://forum.openframeworks.cc/t/ofxthreadedvideo/8783/1

Please post any questions/feedback regarding ofxThreadedVideo to that thread

Would be great if linux/windows users could test and let me know if it works…

1 Like

I was just about to post about this “old” addon when now I see that you created a new one !
I will try out the “new” one soon, thanx a lot !! :slight_smile:

Re: “old” - Thanx and very nice!! Worked for me on Win XP (specs in signature) :slight_smile:
Re: Your examples, very kind of you to provide these for us, but a few things I thought I’d share:

  • Holding space bar to increase loading time also increases movie speed and that may not be desirable
  • Maybe after confirmation of the existence of videos, check for the videos with the smallest and largest number of frames and base calculation on those combining figures instead of 150 frames ??

Ok, so maybe the info below will not be of use to anyone ?? @gameover - below works for me, but correct me if I’m wrong in any respect :wink:
I added this code to the LoadEvents example for us beginners; it just draws the 1st video (instead of blank screen & text) and gives instructions to press “space bar” to load next video :wink:

  
// testApp.h  
int count, goInit;  
  
// testApp.cpp - setup()  
goInit = 1; // first time program runs draw first video: 1 = ON // 0 = OFF  
  
// In testApp.cpp - draw()  
    if (numberOfMovies > 0 && goInit == 1) { // if list of movies detected & 1st time pgm runs, draw 1st video  
        video.loadMovie(dir.getPath(0)); // 1st video in 1st array; for example, if 3 videos exist; dir.getPath[0]=video1, dir.getPath[1]=video2, dir.getPath[2]=video3  
        video.draw(0,0);  
        goInit = 0; // now turn off ( 0 = OFF ), let super-duper loadNextVideo() handle the rest as usual :)  
        count++ ; } // have to increment count otherwise it repeats loading 1st video drawn ;)  
    else {  
        video.draw(0,0);  
    }  
  
    string msg = "****** PRESS SPACE BAR TO LOAD NEXT MOVIE ******\n\n";  
    // retained rest of your text but not posted here; below added "int()" your FPS (to fit everything on screen), and added numberOfMovies to string  
    msg += "FPS: " + ofToString(int(ofGetFrameRate())) + "   numberOfMovies=" + ofToString(numberOfMovies);  
  
  

PS: Increased window size in main.cpp too