// // MediaServer.cpp // example // // Created by felix on 13.09.14. // // #include "MediaServer.h" namespace ofx { namespace piMapper { MediaServer::MediaServer() : videoWatcher(ofToDataPath(DEFAULT_VIDEOS_DIR, true), SourceType::SOURCE_TYPE_VIDEO), imageWatcher(ofToDataPath(DEFAULT_IMAGES_DIR, true), SourceType::SOURCE_TYPE_IMAGE), piVideoWatcher(PI_IMAGES_DIR, SourceType::SOURCE_TYPE_VIDEO), piImageWatcher(PI_IMAGES_DIR, SourceType::SOURCE_TYPE_IMAGE){ addWatcherListeners(); } MediaServer::~MediaServer(){ removeWatcherListeners(); } int MediaServer::getNumImages(){ int numLocalImages = imageWatcher.getFilePaths().size(); int numPiImages = piImageWatcher.getFilePaths().size(); int sum = numLocalImages + numPiImages; return sum; } int MediaServer::getNumVideos(){ int numLocalVideos = videoWatcher.getFilePaths().size(); int numPiVideos = piVideoWatcher.getFilePaths().size(); int sum = numLocalVideos + numPiVideos; return sum; } int MediaServer::getNumFboSources(){ return fboSources.size(); } vector & MediaServer::getImagePaths(){ vector & localPaths = imageWatcher.getFilePaths(); vector & piPaths = piImageWatcher.getFilePaths(); _tempImagePaths.clear(); _tempImagePaths.insert(_tempImagePaths.end(), localPaths.begin(), localPaths.end()); _tempImagePaths.insert(_tempImagePaths.end(), piPaths.begin(), piPaths.end()); return _tempImagePaths; } vector MediaServer::getImageNames(){ vector imageNames; for(int i = 0; i < getNumImages(); i++){ // Split image path vector pathParts = ofSplitString(getImagePaths()[i], "/"); // And get only the last piece string name = pathParts[pathParts.size() - 1]; imageNames.push_back(name); } return imageNames; } vector MediaServer::getFboSourceNames(){ vector fboSourceNames; for(int i = 0; i < fboSources.size(); i++){ fboSourceNames.push_back(fboSources[i]->getName()); } return fboSourceNames; } vector & MediaServer::getVideoPaths(){ vector & localPaths = videoWatcher.getFilePaths(); vector & piPaths = piVideoWatcher.getFilePaths(); _tempVideoPaths.clear(); _tempVideoPaths.insert(_tempVideoPaths.begin(), localPaths.begin(), localPaths.end()); _tempVideoPaths.insert(_tempVideoPaths.begin(), piPaths.begin(), piPaths.end()); return _tempVideoPaths; } vector MediaServer::getVideoNames(){ vector videoNames; for(int i = 0; i < getNumVideos(); i++){ // Split video path vector pathParts = ofSplitString(getVideoPaths()[i], "/"); // And get only the last piece string name = pathParts[pathParts.size() - 1]; videoNames.push_back(name); } return videoNames; } BaseSource * MediaServer::loadMedia(string & path, int mediaType){ // Chose load method depending on type if(mediaType == SourceType::SOURCE_TYPE_IMAGE){ return loadImage(path); }else if(mediaType == SourceType::SOURCE_TYPE_VIDEO){ return loadVideo(path); }else if(mediaType == SourceType::SOURCE_TYPE_FBO){ return loadFboSource(path); }else{ stringstream ss; ss << "Can not load media of unknown type: " << mediaType; ofLogFatalError("MediaServer") << ss.str(); exit(EXIT_FAILURE); } return 0; } BaseSource * MediaServer::loadImage(string & path){ ImageSource * imageSource = 0; // Check if this image is already loaded bool isImageLoaded = false; if(loadedSources.count(path)){ imageSource = static_cast (loadedSources[path]); isImageLoaded = true; } // If image is loaded if(isImageLoaded){ // Increase reference count of this source //referenceCount[path]++; imageSource->referenceCount++; stringstream refss; refss << "Current reference count for " << path << " = " << imageSource->referenceCount; ofLogNotice("MediaServer") << refss.str(); // Notify objects registered to onImageLoaded event stringstream ss; ss << "Image " << path << " already loaded"; ofLogNotice("MediaServer") << ss.str(); ofNotifyEvent(onImageLoaded, path, this); return imageSource; } // Else load fresh imageSource = new ImageSource(); imageSource->loadImage(path); loadedSources[path] = imageSource; // Set reference count of this image path to 1 //referenceCount[path] = 1; stringstream refss; refss << "Initialized reference count of " << path << " to " << imageSource->referenceCount; ofLogNotice("MediaServer") << refss.str(); // Notify objects registered to onImageLoaded event ofNotifyEvent(onImageLoaded, path, this); return imageSource; } void MediaServer::unloadImage(string & path){ ImageSource * source = static_cast (getSourceByPath(path)); ofLogNotice("MediaServer") << "Unload image, current reference count: " << source->referenceCount; source->referenceCount--; // Unload only if reference count is less or equal to 0 ofLogNotice("MediaServer") << "New reference count: " << source->referenceCount; if(source->referenceCount > 0){ ofLogNotice("MediaServer") << "Not unloading image as it is being referenced elsewhere"; return; } // Reference count 0 or less, unload image stringstream ss; ss << "Removing image " << path; ofLogNotice("MediaServer") << ss.str(); // Destroy image source if(loadedSources.count(path)){ ofLogNotice("MediaServer") << "Source count BEFORE image removal: " << loadedSources.size() << endl; loadedSources[path]->clear(); map ::iterator it = loadedSources.find(path); delete it->second; loadedSources.erase(it); ofLogNotice("MediaServer") << "Source count AFTER image removal: " << loadedSources.size() << endl; ofNotifyEvent(onImageUnloaded, path, this); return; } // Something wrong here, we should be out of the routine by now stringstream failss; failss << "Failed to remove image source: " << path; ofLogFatalError("MediaServer") << failss.str(); exit(EXIT_FAILURE); } BaseSource * MediaServer::loadVideo(string & path){ VideoSource * videoSource = 0; // Check if this video is already loaded bool isVideoLoaded = false; if(loadedSources.count(path)){ videoSource = static_cast (loadedSources[path]); isVideoLoaded = true; } // If is loaded if(isVideoLoaded){ // Increase reference count of this source videoSource->referenceCount++; stringstream refss; refss << "Current reference count for " << path << " = " << videoSource->referenceCount; ofLogNotice("MediaServer") << refss.str(); // Notify objects registered to onImageLoaded event stringstream ss; ss << "Video " << path << " already loaded"; ofLogNotice("MediaServer") << ss.str(); ofNotifyEvent(onVideoLoaded, path, this); return videoSource; } // Else load fresh videoSource = new VideoSource(); videoSource->loadVideo(path); loadedSources[path] = videoSource; // Set reference count of this image path to 1 //referenceCount[path] = 1; stringstream refss; refss << "Initialized reference count of " << path << " to " << videoSource->referenceCount; ofLogNotice("MediaServer") << refss.str(); ofNotifyEvent(onVideoLoaded, path, this); return videoSource; } void MediaServer::unloadVideo(string & path){ VideoSource * videoSource = static_cast (getSourceByPath(path)); // Decrease reference count of the video //referenceCount[path]--; videoSource->referenceCount--; // Unload only if reference count is less or equal to 0 if(videoSource->referenceCount > 0){ ofLogNotice("MediaServer") << "Not unloading video as it is being referenced elsewhere"; return; } // Reference count 0 or less, let's unload the video ofLogNotice("MediaServer") << "Removing video " << path; // Distroy video source if(loadedSources.count(path)){ ofLogNotice("MediaServer") << "Source count before video removal: " << loadedSources.size() << endl; videoSource->clear(); map ::iterator it = loadedSources.find(path); delete it->second; loadedSources.erase(it); ofLogNotice("MediaServer") << "Source count after video removal: " << loadedSources.size() << endl; ofNotifyEvent(onVideoUnloaded, path, this); return; } // Something wrong here, we should be out of the routine by now stringstream failss; failss << "Failed to remove video source: " << path; ofLogFatalError("MediaServer") << failss.str(); exit(EXIT_FAILURE); } void MediaServer::unloadMedia(string & path){ if(loadedSources.count(path)){ BaseSource * mediaSource = getSourceByPath(path); if(mediaSource->getType() == SourceType::SOURCE_TYPE_IMAGE){ unloadImage(path); }else if(mediaSource->getType() == SourceType::SOURCE_TYPE_VIDEO){ unloadVideo(path); }else if(mediaSource->getType() == SourceType::SOURCE_TYPE_FBO){ unloadFboSource(path); }else{ // Oh my god, what to do!? Relax and exit. ofLogFatalError("MediaServer") << "Attempt to unload media of unknown type"; exit(EXIT_FAILURE); } }else{ ofLogNotice("MediaServer") << "Nothing to unload"; } } // Clear all loaded media void MediaServer::clear(){ typedef map ::iterator it_type; for(it_type i = loadedSources.begin(); i != loadedSources.end(); i++){ // Do not delete FBO source pointers as they are (and should be) initialized elsewhere if(i->second->getType() != SourceType::SOURCE_TYPE_FBO){ delete i->second; } } loadedSources.clear(); } // TODO: getLoadedSourceByPath BaseSource * MediaServer::getSourceByPath(string & mediaPath){ if(loadedSources.count(mediaPath)){ return loadedSources[mediaPath]; } // Source not found, exit with error stringstream ss; ss << "Could not find source by path: " << mediaPath; ofLogFatalError("MediaServer") << ss.str(); exit(EXIT_FAILURE); } string MediaServer::getDefaultImageDir(){ return DEFAULT_IMAGES_DIR; } string MediaServer::getDefaultVideoDir(){ return DEFAULT_VIDEOS_DIR; } string MediaServer::getDefaultMediaDir(int sourceType){ if(sourceType == SourceType::SOURCE_TYPE_IMAGE){ return getDefaultImageDir(); }else if(sourceType == SourceType::SOURCE_TYPE_VIDEO){ return getDefaultVideoDir(); }else{ stringstream ss; ss << "Could not get default media dir. Unknown source type: " << sourceType; ofLogFatalError("MediaServer") << ss.str(); exit(EXIT_FAILURE); } } void MediaServer::addFboSource(ofx::piMapper::FboSource & fboSource){ ofLogNotice("MediaServer") << "Attempting to add FBO source with name " << fboSource.getName(); // FBO source has to be with unique name for(int i = 0; i < fboSources.size(); i++){ if(fboSources[i]->getName() == fboSource.getName()){ ofLogWarning("MediaServer") << "Attempt to add FBO source with duplicate name"; ofExit(EXIT_FAILURE); // Here we definitely need to fail to avoid confusion } } ofLogNotice("MediaServer") << "Source new, adding"; fboSources.push_back(&fboSource); } // addFboSource BaseSource * MediaServer::loadFboSource(string & fboSourceName){ ofLogNotice("MediaServer") << "Attempting to load FBO source with name " << fboSourceName; // Search for FBO source name in our storage FboSource * source = 0; for(int i = 0; i < fboSources.size(); i++){ if(fboSources[i]->getName() == fboSourceName){ source = fboSources[i]; break; } } // Panic if not in storage if(source == 0){ ofLogError("MediaServer") << "Attempt to load non existing FBO source: " << fboSourceName; ofExit(EXIT_FAILURE); } // Check if it is loaded/activated if(loadedSources.count(fboSourceName)){ // Is loaded, increase reference count and return existing loadedSources[fboSourceName]->referenceCount++; ofLogNotice("MediaServer") << "Current " << fboSourceName << "reference count: " << loadedSources[fboSourceName]->referenceCount; return loadedSources[fboSourceName]; } // else // Not loaded, add to loaded sources and activate // source var should be set by now source->addAppListeners(); source->referenceCount = 1; ofLogNotice("MediaServer") << "Current " << fboSourceName << " reference count: " << source->referenceCount; loadedSources[fboSourceName] = source; return loadedSources[fboSourceName]; } // loadFboSource void MediaServer::unloadFboSource(string & fboSourceName){ ofLogNotice("MediaServer") << "Attempt to unload FBO source " << fboSourceName; // Check if loaded at all if(!loadedSources.count(fboSourceName)){ ofLogWarning("MediaServer") << "FBO source not loaded"; return; } // TODO: remove static cast, make the sources handle reference counting, // enabling and disabling by themselves FboSource * source = static_cast (loadedSources[fboSourceName]); // else decrease reference count source->referenceCount--; ofLogNotice("MediaServer") << "Current " << fboSourceName << "reference count: " << loadedSources[fboSourceName]->referenceCount; // If no references left, disable if(source->referenceCount <= 0){ ofLogNotice("MediaServer") << fboSourceName << " reference count <= 0, removing from loaded sources"; source->referenceCount = 0; source->removeAppListeners(); map ::iterator it = loadedSources.find(fboSourceName); loadedSources.erase(it); ofLogNotice("MediaServer") << "Source count after FBO source removal: " << loadedSources.size() << endl; ofNotifyEvent(onFboSourceUnloaded, fboSourceName, this); } } // unloadFboSource void MediaServer::handleImageAdded(string & path){ ofNotifyEvent(onImageAdded, path, this); } void MediaServer::handleImageRemoved(string & path){ ofNotifyEvent(onImageRemoved, path, this); } void MediaServer::handleVideoAdded(string & path){ ofNotifyEvent(onVideoAdded, path, this); } void MediaServer::handleVideoRemoved(string & path){ ofNotifyEvent(onVideoRemoved, path, this); } void MediaServer::addWatcherListeners(){ ofAddListener(imageWatcher.onItemAdded, this, &MediaServer::handleImageAdded); ofAddListener(imageWatcher.onItemRemoved, this, &MediaServer::handleImageRemoved); ofAddListener(videoWatcher.onItemAdded, this, &MediaServer::handleVideoAdded); ofAddListener(videoWatcher.onItemRemoved, this, &MediaServer::handleVideoRemoved); } void MediaServer::removeWatcherListeners(){ ofRemoveListener(imageWatcher.onItemAdded, this, &MediaServer::handleImageAdded); ofRemoveListener(imageWatcher.onItemRemoved, this, &MediaServer::handleImageRemoved); ofRemoveListener(videoWatcher.onItemAdded, this, &MediaServer::handleVideoAdded); ofRemoveListener(videoWatcher.onItemRemoved, this, &MediaServer::handleVideoRemoved); } } // namespace piMapper } // namespace ofx