videoPlayer class pointer hangs at __psynch_mutexwait

Hi there,

I’m working on quite an extensive app that’s derived from the Most Pixels Ever addon. Using this to play video’s in sync (amongst other things) locally on three machines that are connected to a couple of beamers. Recently I moved my project from oF 0071 to 0072, mainly because it seems to improve video playback. Before I compiled on the 10.6 OSX SDK because some issue with the videoPlayer prevented me from using 10.8 (my own OS version). This went fine and all, but now I seem to have a quite annoying and inconsistant hick-up.

When the app starts it reads out a directory containing video’s and loads these video’s using an instance of the videoPlayer so I can see some more info about the video’s (nr of frames, duration etc.) and write this to an XML file.
Later I send this XML around to check if all instances of my app have the same directory files on all machines. It doesn’t need to hold on to the video instances after this check, thats just needed to gain some information about the videos.

This all happens in a class I called chapterHandler in the readDir function
https://github.com/mickman112/eCinemaSetup/blob/master/src/chapterHandler/chapterHandler.cpp

The strange thing is, when I fire up the app about half the time it hangs, doesn’t give an error or something, but while iterating through the movie files at some point it gets stuck.

Looking into the running processes I can see it stuck at Thread 1 at a process called __psynch_mutexwait
I’ve looked around a bit and I assume this has something to do with threading, it doesn’t seem to like I use a videoPlayer pointer for loading different video’s in a short period. I’ve already managed to reduce the amount of times it gets stuck a bit by only creating and deleting the videoPlayer (tempMov) only once, before I did that for each video I wanted to load.

Anyone has any clue what might be the issue?

Update:

Here are some screenshots of the compiled app and the info I have in my processes (yes I manually pause the app, because compiling goes fine and it doesn’t give an error, it just gets stuck.)

What happens if you make tempMov a property of the Class? Maybe do a check against loadMovie (it returns a bool).

the screenshots are taking forever to load for some reason

dropbox doesn’t seem to like me using their public folder. Ah well, i’ve hosted the screenshots somewhere else now, you should be able to see them.

I’ve made the changes you said, it seems to be a bit better, especially when I start up just one app, but as soon as I try to run two instances on the same computer (haven’t been able to test this yet with two mac’s) it has a really hard time, guess only one in four or five tries it works. Issue seems to stay the same, gets stuck at loading the movies during startup. Here’s the code

chapterHandler.h

  
class handleChapters {  
  
public:  
    handleChapters();  
      
    void setup(string ID);  
    void update();  
    void readDir();  
    void writeXML();  
    void checkFiles();  
      
    string          clientID;  
      
    // read dir stuff  
    ofDirectory     dir;  
    ofFile          file;  
          
    // okay might seem weird, but we need two vector objects for storing  
    // all this info before we write it to an XML, just wanna be safe  
    struct FilmInfo {  
        string      file;  
        string      name;  
        int         duration;  
        int         numFrames;  
        int         filesize;  
        int         width;  
        int         height;  
        bool        sameSettings;  
    };  
    vector<FilmInfo>    filmInfo;  
      
    struct Chapters {  
        string      name;  
        FilmInfo    left;  
        FilmInfo    middle;  
        FilmInfo    right;  
        bool        complete;  
        bool        inOrder;  
    };  
    vector<Chapters>    chapters;  
      
    // xml stuff  
    ofxXmlSettings XML;  
    string xmlStructure;  
      
    string totalXmlString;  
      
    struct xmlPart {  
        string  part;  
        bool    checked = false;  
    };  
    vector<xmlPart> partXML;  
      
    int lastTagNumber;  
    int lastChapNumber;  
      
    //ofEvent<int>        buildGUIEvent;  
    ofEvent<int>        addAllVideosEvent;  
      
      
private:  
    // need to load movies to get some actual data on them  
    ofVideoPlayer  *tempMov;  
};  
  

chapterHandler.cpp - readDir function

  
void handleChapters::readDir(){  
      
    printf("reading directory sir\n");  
      
    // load content  
    dir.listDir("content/");  
	dir.sort(); // in linux the file system doesn't return file lists ordered in alphabetical order  
      
	//allocate the vector to have as many strings as files  
	if( dir.size() ){  
		chapters.assign(dir.size(), Chapters());  
	}  
      
    //tempMov = new ofVideoPlayer();  
      
	// you can now iterate through the files and load them into the Chapters vector  
	for(int i = 0; i < (int)dir.size(); i++){  
          
        file.open(dir.getPath(i));  
        if(file.isDirectory()){  
            dir.sort(); // do this again to alfabetize  
              
            chapters[i].complete = false; // don't worry kids, we're just not certain yet  
            chapters[i].inOrder  = false; // let me get back to that  
              
            chapters[i].name = dir.getName(i);  
            printf("%s\n",chapters[i].name.c_str());  
            // getting filename should be a folder  
              
              
            // write a new chapter to the XMl object  
            if( XML.pushTag("movies", lastTagNumber) ){  
                  
                dir.listDir(dir.getPath(i)+"/");  
                dir.sort();  
                  
                int lastChapNumber = XML.addTag("chapter");  
                // writing chapter folder name to XML object  
                XML.setValue("chapter:name", chapters[i].name, lastChapNumber);  
                  
                //printf("tagNum: %i\n",lastChapNumber);  
                //printf("lastTagNumber: %i\n",lastTagNumber);  
                  
                // iterate through directory  
                for(int f = 0; f < (int)dir.size(); f++){  
                    file.open(dir.getPath(f));  
                      
                    printf("iterating through directory %i\n",f);  
                      
                    if(file.isFile()){  
                        file.open(dir.getPath(f));  
                          
                        // check if movie is named L, M or R then add to filmInfo object thats inside Chapters  
                        // furthermore we check for several aspects of the film files, some info is only gained  
                        // when actually loading the video, so thats where the tempMov kicks in. This is a bit  
                        // processor heavy though, so do't do it all the time!  
                        string baseName = file.getBaseName();  
                        string firstChar = "";  
                        firstChar += baseName[0];  
                          
                        printf("filename: %s\n", dir.getName(f).c_str());  
                                                  
                        if(firstChar == "L"){ // left screen duh  
                            chapters[i].left.file = dir.getPath(f);  
                            chapters[i].left.name = dir.getName(f);  
                            chapters[i].left.filesize = file.getSize();  
                              
                            tempMov = new ofVideoPlayer();  
                            if (tempMov->loadMovie(chapters[i].left.file)) {  
                                chapters[i].left.width    = tempMov->getWidth();  
                                chapters[i].left.height   = tempMov->getHeight();  
                                chapters[i].left.duration = tempMov->getDuration();  
                                chapters[i].left.numFrames = tempMov->getTotalNumFrames();  
                            }  
                            delete tempMov;  
                            //tempMov.close();  
                            chapters[i].left.sameSettings = false; // figure this out later  
                              
                            if( XML.pushTag("chapter", lastChapNumber) ){  
                                int tagNum = XML.addTag("left");  
                                // writing film info of this thing to XML  
                                XML.setValue("left:file", chapters[i].left.file, tagNum);  
                                XML.setValue("left:name", chapters[i].left.name, tagNum);  
                                XML.setValue("left:duration", chapters[i].left.duration, tagNum);  
                                XML.setValue("left:frames", chapters[i].left.numFrames, tagNum);  
                                XML.setValue("left:filesize", chapters[i].left.filesize, tagNum);  
                                XML.setValue("left:width", chapters[i].left.width, tagNum);  
                                XML.setValue("left:height", chapters[i].left.height, tagNum);  
                                XML.popTag();  
                            }  
                        } else if(firstChar == "M"){ // middle screen duh  
                            chapters[i].middle.file = dir.getPath(f);  
                            chapters[i].middle.name = dir.getName(f);  
                            chapters[i].middle.filesize = file.getSize();  
                              
                            tempMov = new ofVideoPlayer();  
                            if (tempMov->loadMovie(chapters[i].middle.file)) {  
                                chapters[i].middle.width    = tempMov->getWidth();  
                                chapters[i].middle.height   = tempMov->getHeight();  
                                chapters[i].middle.duration = tempMov->getDuration();  
                                chapters[i].middle.numFrames = tempMov->getTotalNumFrames();  
                            }  
                            delete tempMov;  
                            //tempMov.close();  
                            chapters[i].middle.sameSettings = false; // figure this out later  
                              
                            if( XML.pushTag("chapter", lastChapNumber) ){  
                                int tagNum = XML.addTag("middle");  
                                // writing film info of this thing to XML  
                                XML.setValue("middle:file", chapters[i].middle.file, tagNum);  
                                XML.setValue("middle:name", chapters[i].middle.name, tagNum);  
                                XML.setValue("middle:duration", chapters[i].middle.duration, tagNum);  
                                XML.setValue("middle:frames", chapters[i].left.numFrames, tagNum);  
                                XML.setValue("middle:filesize", chapters[i].middle.filesize, tagNum);  
                                XML.setValue("middle:width", chapters[i].middle.width, tagNum);  
                                XML.setValue("middle:height", chapters[i].middle.height, tagNum);  
                                XML.popTag();  
                            }  
                        } else if(firstChar == "R"){ // right screen duh  
                            chapters[i].right.file = dir.getPath(f);  
                            chapters[i].right.name = dir.getName(f);  
                            chapters[i].right.filesize = file.getSize();  
                              
                            tempMov = new ofVideoPlayer();  
                            if (tempMov->loadMovie(chapters[i].right.file)) {  
                                chapters[i].right.width    = tempMov->getWidth();  
                                chapters[i].right.height   = tempMov->getHeight();  
                                chapters[i].right.duration = tempMov->getDuration();  
                                chapters[i].right.numFrames = tempMov->getTotalNumFrames();  
                            }  
                            delete tempMov;  
                            //tempMov.close();  
                            chapters[i].right.sameSettings = false; // figure this out later  
                              
                            if( XML.pushTag("chapter", lastChapNumber) ){  
                                int tagNum = XML.addTag("right");  
                                // writing film info of this thing to XML  
                                XML.setValue("right:file", chapters[i].right.file, tagNum);  
                                XML.setValue("right:name", chapters[i].right.name, tagNum);  
                                XML.setValue("right:duration", chapters[i].right.duration, tagNum);  
                                XML.setValue("right:frames", chapters[i].left.numFrames, tagNum);  
                                XML.setValue("right:filesize", chapters[i].right.filesize, tagNum);  
                                XML.setValue("right:width", chapters[i].right.width, tagNum);  
                                XML.setValue("right:height", chapters[i].right.height, tagNum);  
                                XML.popTag();  
                            }  
                        }  
                    }  
                }  
                dir.listDir("content/");  
                dir.sort();  
                // pop out of chapter  
                XML.popTag();  
            }  
              
        } else {  
            printf("no directory senior! - %s\n", dir.getPath(i).c_str());  
        }  
    }  
    checkFiles(); // checking to see if all files are in order  
    writeXML(); // write it to an XML file, makes it easy to check whats wrong  
      
    // chopping up the xml file into 300 char pieces so I can send it over the MPE network for checking  
    XML.copyXmlToString(totalXmlString);  
    totalXmlString.erase(std::remove(totalXmlString.begin(), totalXmlString.end(), '\n'), totalXmlString.end());  
    totalXmlString.erase(std::remove(totalXmlString.begin(), totalXmlString.end(), ' '), totalXmlString.end());  
    totalXmlString.erase(std::remove(totalXmlString.begin(), totalXmlString.end(), ','), totalXmlString.end());  
    int chopLength = 300;  
    float fChops = float(totalXmlString.size())/float(chopLength);  
    float fChopsRoundUP = ceil(fChops);  
    int numChops = int(fChopsRoundUP);  
    partXML.resize(numChops);  
    for (int i = 0; i < numChops; i++) {  
        partXML[i].part = totalXmlString.substr(i*chopLength,chopLength);  
        partXML[i].checked = false;  
    }  
  
    //delete tempMov;  
}  

Why are you using a pointer for the videoplayer, it seems like is only to get movie properties. I did something like this but i used a vector of videoplayer and update that vector to load. Maybe is easier to you to put the info about the movie in a xml file and load the info from that

  
  
tempMov = new ofVideoPlayer();    
if (tempMov->loadMovie(chapters[i].right.file)) {    
chapters[i].right.width    = tempMov->getWidth();    
chapters[i].right.height   = tempMov->getHeight();    
chapters[i].right.duration = tempMov->getDuration();    
chapters[i].right.numFrames = tempMov->getTotalNumFrames();    
}    
delete tempMov;  
  

i think that your problem comes from here, correctme if im wrong but i think that the code doesnt wait for the video to load.

  
  
setup(){  
tempMov = new ofVideoPlayer();    
}  
  
update(){  
tempMov.update();  
if(tempMov.isLoaded()){  
//se ha cargado  
}  
}  
  
  

my english its no good so i hope that your understand what i tried to say…

Thanks for the suggestion pandereto, didn’t think about updating the videoclass, mostly because I don’t use it to play video anyway. Not sure if the code does or doesn’t wait for the video to be loaded, in my logs it just stops during loading.

Though I think I’ve found a solution (was this what you ment by using a vector of the class?), it seems to work fairly well, not sure if it’s the pretiest option, but so far I’m getting good results.

http://forum.openframeworks.cc/t/allocating-and-releasing-videos/11003/5

PS: The reason this class exists is to read out the video’s and put the data in an XML and send that around the network for checking. I’m working with lots of video, some of it being created on the same night of the performance, so I really want to be sure the content on all computers is exactly the same. That’s why I can’t create the XML beforehand.

  
  
vector<ofVideoPlayer*> videos;  
  

  
  
void handleChapters::readDir(){  
      
    printf("reading directory sir\n");  
      
    // load content  
    dir.listDir("content/");  
	dir.sort(); // in linux the file system doesn't return file lists ordered in alphabetical order  
      
	//allocate the vector to have as many strings as files  
	if( dir.size() ){  
		chapters.assign(dir.size(), Chapters());  
	}  
      
    //tempMov = new ofVideoPlayer();  
      
	// you can now iterate through the files and load them into the Chapters vector  
	for(int i = 0; i < (int)dir.size(); i++){  
          
        file.open(dir.getPath(i));  
        if(file.isDirectory()){  
            dir.sort(); // do this again to alfabetize  
              
            chapters[i].complete = false; // don't worry kids, we're just not certain yet  
            chapters[i].inOrder  = false; // let me get back to that  
              
            chapters[i].name = dir.getName(i);  
            printf("%s\n",chapters[i].name.c_str());  
            // getting filename should be a folder  
              
              
            // write a new chapter to the XMl object  
            if( XML.pushTag("movies", lastTagNumber) ){  
                  
                dir.listDir(dir.getPath(i)+"/");  
                dir.sort();  
                  
                int lastChapNumber = XML.addTag("chapter");  
                // writing chapter folder name to XML object  
                XML.setValue("chapter:name", chapters[i].name, lastChapNumber);  
                  
                //printf("tagNum: %i\n",lastChapNumber);  
                //printf("lastTagNumber: %i\n",lastTagNumber);  
                  
                // iterate through directory  
                for(int f = 0; f < (int)dir.size(); f++){  
                    file.open(dir.getPath(f));  
                      
                    printf("iterating through directory %i\n",f);  
                      
                    if(file.isFile()){  
                        file.open(dir.getPath(f));  
                          
                        // check if movie is named L, M or R then add to filmInfo object thats inside Chapters  
                        // furthermore we check for several aspects of the film files, some info is only gained  
                        // when actually loading the video, so thats where the tempMov kicks in. This is a bit  
                        // processor heavy though, so do't do it all the time!  
                        string baseName = file.getBaseName();  
                        string firstChar = "";  
                        firstChar += baseName[0];  
                          
                        printf("filename: %s\n", dir.getName(f).c_str());  
                                                  
                        if(firstChar == "L"){ // left screen duh  
                            chapters[i].left.file = dir.getPath(f);  
                            chapters[i].left.name = dir.getName(f);  
                            chapters[i].left.filesize = file.getSize();  
                              
                            //tempMov = new ofVideoPlayer();  
                            //tempMov.loadMovie(chapters[i].left.file);  
                            ofVideoPlayer *vid = new ofVideoPlayer;  
                            vid->loadMovie(chapters[i].left.file);  
                            //vid->play();  
                            //vid->marked=false;    
                            videos.push_back(vid);  
  
                            if (videos.back()->isLoaded()) {  
                                chapters[i].left.width    = videos.back()->getWidth();  
                                chapters[i].left.height   = videos.back()->getHeight();  
                                chapters[i].left.duration = videos.back()->getDuration();  
                                chapters[i].left.numFrames = videos.back()->getTotalNumFrames();  
                            }  
  
                              
                            //delete tempMov;  
                            //tempMov.close();  
                            chapters[i].left.sameSettings = false; // figure this out later  
                              
                            if( XML.pushTag("chapter", lastChapNumber) ){  
                                int tagNum = XML.addTag("left");  
                                // writing film info of this thing to XML  
                                XML.setValue("left:file", chapters[i].left.file, tagNum);  
                                XML.setValue("left:name", chapters[i].left.name, tagNum);  
                                XML.setValue("left:duration", chapters[i].left.duration, tagNum);  
                                XML.setValue("left:frames", chapters[i].left.numFrames, tagNum);  
                                XML.setValue("left:filesize", chapters[i].left.filesize, tagNum);  
                                XML.setValue("left:width", chapters[i].left.width, tagNum);  
                                XML.setValue("left:height", chapters[i].left.height, tagNum);  
                                XML.popTag();  
                            }  
                        } else if(firstChar == "M"){ // middle screen duh  
                            chapters[i].middle.file = dir.getPath(f);  
                            chapters[i].middle.name = dir.getName(f);  
                            chapters[i].middle.filesize = file.getSize();  
                              
                            //tempMov = new ofVideoPlayer();  
                            //tempMov.loadMovie(chapters[i].middle.file);  
                            ofVideoPlayer *vid = new ofVideoPlayer;  
                            vid->loadMovie(chapters[i].middle.file);  
                            //vid->play();  
                            //vid->marked=false;  
                            videos.push_back(vid);  
                              
                            if (videos.back()->isLoaded()) {  
                                chapters[i].middle.width    = videos.back()->getWidth();  
                                chapters[i].middle.height   = videos.back()->getHeight();  
                                chapters[i].middle.duration = videos.back()->getDuration();  
                                chapters[i].middle.numFrames = videos.back()->getTotalNumFrames();  
                            }  
                            //delete tempMov;  
                            //tempMov.close();  
                            chapters[i].middle.sameSettings = false; // figure this out later  
                              
                            if( XML.pushTag("chapter", lastChapNumber) ){  
                                int tagNum = XML.addTag("middle");  
                                // writing film info of this thing to XML  
                                XML.setValue("middle:file", chapters[i].middle.file, tagNum);  
                                XML.setValue("middle:name", chapters[i].middle.name, tagNum);  
                                XML.setValue("middle:duration", chapters[i].middle.duration, tagNum);  
                                XML.setValue("middle:frames", chapters[i].left.numFrames, tagNum);  
                                XML.setValue("middle:filesize", chapters[i].middle.filesize, tagNum);  
                                XML.setValue("middle:width", chapters[i].middle.width, tagNum);  
                                XML.setValue("middle:height", chapters[i].middle.height, tagNum);  
                                XML.popTag();  
                            }  
                        } else if(firstChar == "R"){ // right screen duh  
                            chapters[i].right.file = dir.getPath(f);  
                            chapters[i].right.name = dir.getName(f);  
                            chapters[i].right.filesize = file.getSize();  
                              
                            //tempMov = new ofVideoPlayer();  
                            //tempMov.loadMovie(chapters[i].right.file);  
                              
                            ofVideoPlayer *vid = new ofVideoPlayer;  
                            vid->loadMovie(chapters[i].right.file);  
                            //vid->play();  
                            //vid->marked=false;  
                            videos.push_back(vid);  
  
                            if (videos.back()->isLoaded()) {  
                                chapters[i].right.width    = videos.back()->getWidth();  
                                chapters[i].right.height   = videos.back()->getHeight();  
                                chapters[i].right.duration = videos.back()->getDuration();  
                                chapters[i].right.numFrames = videos.back()->getTotalNumFrames();  
                            }  
                            //delete tempMov;  
                            //tempMov.close();  
                            chapters[i].right.sameSettings = false; // figure this out later  
                              
                            if( XML.pushTag("chapter", lastChapNumber) ){  
                                int tagNum = XML.addTag("right");  
                                // writing film info of this thing to XML  
                                XML.setValue("right:file", chapters[i].right.file, tagNum);  
                                XML.setValue("right:name", chapters[i].right.name, tagNum);  
                                XML.setValue("right:duration", chapters[i].right.duration, tagNum);  
                                XML.setValue("right:frames", chapters[i].left.numFrames, tagNum);  
                                XML.setValue("right:filesize", chapters[i].right.filesize, tagNum);  
                                XML.setValue("right:width", chapters[i].right.width, tagNum);  
                                XML.setValue("right:height", chapters[i].right.height, tagNum);  
                                XML.popTag();  
                            }  
                        }  
                    }  
                }  
                dir.listDir("content/");  
                dir.sort();  
                // pop out of chapter  
                XML.popTag();  
            }  
              
        } else {  
            printf("no directory senior! - %s\n", dir.getPath(i).c_str());  
        }  
    }  
    checkFiles(); // checking to see if all files are in order  
    writeXML(); // write it to an XML file, makes it easy to check whats wrong  
      
    // chopping up the xml file into 300 char pieces so I can send it over the MPE network for checking  
    XML.copyXmlToString(totalXmlString);  
    totalXmlString.erase(std::remove(totalXmlString.begin(), totalXmlString.end(), '\n'), totalXmlString.end());  
    totalXmlString.erase(std::remove(totalXmlString.begin(), totalXmlString.end(), ' '), totalXmlString.end());  
    totalXmlString.erase(std::remove(totalXmlString.begin(), totalXmlString.end(), ','), totalXmlString.end());  
    int chopLength = 300;  
    float fChops = float(totalXmlString.size())/float(chopLength);  
    float fChopsRoundUP = ceil(fChops);  
    int numChops = int(fChopsRoundUP);  
    partXML.resize(numChops);  
    for (int i = 0; i < numChops; i++) {  
        partXML[i].part = totalXmlString.substr(i*chopLength,chopLength);  
        partXML[i].checked = false;  
    }  
  
    //delete tempMov;  
      
    vector<ofVideoPlayer*>::iterator its;  
    for(its = videos.begin(); its != videos.end(); its++){  
        (*its)->~ofVideoPlayer();  
        videos.erase(its);  
        break;  
          
    }  
}  
  

Thanks for the suggestion pandereto, didn’t think about updating the videoclass, mostly because I don’t use it to play video anyway.

i think that you have to do an update to make the video to load…

yes, something like your are saying. I think that its a good aproach

vector<ofVideoPlayer*> videos;

i use a index to say the active index so i have something like

videos.at(videoIndex)->update();

and so on…

Also, some warning about that.
In my project i used a lot of bigs videos arround a total of 15Gb, i used gstreamer because im running on a pc, and found that when use a lot of bigmovie and want to change playback very fast… sometimes it crash. I resolved that doing two parts in the app, so i first load a half and later delete that and load the another part.

good luk