svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "FeatureExtractionPluginFactory.h" 00017 #include "PluginIdentifier.h" 00018 00019 #include <vamp-hostsdk/PluginHostAdapter.h> 00020 #include <vamp-hostsdk/PluginWrapper.h> 00021 00022 #include "system/System.h" 00023 00024 #include <QDir> 00025 #include <QFile> 00026 #include <QFileInfo> 00027 #include <QTextStream> 00028 00029 #include <iostream> 00030 00031 #include "base/Profiler.h" 00032 00033 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 00034 00035 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper { 00036 public: 00037 PluginDeletionNotifyAdapter(Vamp::Plugin *plugin, 00038 FeatureExtractionPluginFactory *factory) : 00039 PluginWrapper(plugin), m_factory(factory) { } 00040 virtual ~PluginDeletionNotifyAdapter(); 00041 protected: 00042 FeatureExtractionPluginFactory *m_factory; 00043 }; 00044 00045 PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() 00046 { 00047 // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn 00048 Vamp::Plugin *p = m_plugin; 00049 delete m_plugin; 00050 m_plugin = 0; 00051 // acceptable use after free here, as pluginDeleted uses p only as 00052 // pointer key and does not deref it 00053 if (m_factory) m_factory->pluginDeleted(p); 00054 } 00055 00056 static FeatureExtractionPluginFactory *_nativeInstance = 0; 00057 00058 FeatureExtractionPluginFactory * 00059 FeatureExtractionPluginFactory::instance(QString pluginType) 00060 { 00061 if (pluginType == "vamp") { 00062 if (!_nativeInstance) { 00063 // SVDEBUG << "FeatureExtractionPluginFactory::instance(" << pluginType// << "): creating new FeatureExtractionPluginFactory" << endl; 00064 _nativeInstance = new FeatureExtractionPluginFactory(); 00065 } 00066 return _nativeInstance; 00067 } 00068 00069 else return 0; 00070 } 00071 00072 FeatureExtractionPluginFactory * 00073 FeatureExtractionPluginFactory::instanceFor(QString identifier) 00074 { 00075 QString type, soName, label; 00076 PluginIdentifier::parseIdentifier(identifier, type, soName, label); 00077 return instance(type); 00078 } 00079 00080 std::vector<QString> 00081 FeatureExtractionPluginFactory::getPluginPath() 00082 { 00083 if (!m_pluginPath.empty()) return m_pluginPath; 00084 00085 std::vector<std::string> p = Vamp::PluginHostAdapter::getPluginPath(); 00086 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str()); 00087 return m_pluginPath; 00088 } 00089 00090 std::vector<QString> 00091 FeatureExtractionPluginFactory::getAllPluginIdentifiers() 00092 { 00093 FeatureExtractionPluginFactory *factory; 00094 std::vector<QString> rv; 00095 00096 factory = instance("vamp"); 00097 if (factory) { 00098 std::vector<QString> tmp = factory->getPluginIdentifiers(); 00099 for (size_t i = 0; i < tmp.size(); ++i) { 00100 // cerr << "identifier: " << tmp[i] << endl; 00101 rv.push_back(tmp[i]); 00102 } 00103 } 00104 00105 // Plugins can change the locale, revert it to default. 00106 RestoreStartupLocale(); 00107 00108 return rv; 00109 } 00110 00111 std::vector<QString> 00112 FeatureExtractionPluginFactory::getPluginIdentifiers() 00113 { 00114 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); 00115 00116 std::vector<QString> rv; 00117 std::vector<QString> path = getPluginPath(); 00118 00119 for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) { 00120 00121 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00122 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << i-<< endl; 00123 #endif 00124 00125 QDir pluginDir(*i, PLUGIN_GLOB, 00126 QDir::Name | QDir::IgnoreCase, 00127 QDir::Files | QDir::Readable); 00128 00129 for (unsigned int j = 0; j < pluginDir.count(); ++j) { 00130 00131 QString soname = pluginDir.filePath(pluginDir[j]); 00132 00133 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00134 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: trying potential library " << soname << endl; 00135 #endif 00136 00137 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); 00138 00139 if (!libraryHandle) { 00140 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl; 00141 continue; 00142 } 00143 00144 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00145 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: It's a library all right, checking for descriptor" << endl; 00146 #endif 00147 00148 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) 00149 DLSYM(libraryHandle, "vampGetPluginDescriptor"); 00150 00151 if (!fn) { 00152 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl; 00153 if (DLCLOSE(libraryHandle) != 0) { 00154 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; 00155 } 00156 continue; 00157 } 00158 00159 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00160 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl; 00161 #endif 00162 00163 const VampPluginDescriptor *descriptor = 0; 00164 int index = 0; 00165 00166 std::map<std::string, int> known; 00167 bool ok = true; 00168 00169 while ((descriptor = fn(VAMP_API_VERSION, index))) { 00170 00171 if (known.find(descriptor->identifier) != known.end()) { 00172 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library " 00173 << soname 00174 << " returns the same plugin identifier \"" 00175 << descriptor->identifier << "\" at indices " 00176 << known[descriptor->identifier] << " and " 00177 << index << endl; 00178 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl; 00179 ok = false; 00180 break; 00181 } else { 00182 known[descriptor->identifier] = index; 00183 } 00184 00185 ++index; 00186 } 00187 00188 if (ok) { 00189 00190 index = 0; 00191 00192 while ((descriptor = fn(VAMP_API_VERSION, index))) { 00193 00194 QString id = PluginIdentifier::createIdentifier 00195 ("vamp", soname, descriptor->identifier); 00196 rv.push_back(id); 00197 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00198 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl; 00199 #endif 00200 ++index; 00201 } 00202 } 00203 00204 if (DLCLOSE(libraryHandle) != 0) { 00205 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; 00206 } 00207 } 00208 } 00209 00210 generateTaxonomy(); 00211 00212 return rv; 00213 } 00214 00215 QString 00216 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir) 00217 { 00218 QString file = ""; 00219 00220 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00221 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile(\"" 00222 << soname << "\", \"" << inDir << "\")" 00223 << endl; 00224 #endif 00225 00226 if (inDir != "") { 00227 00228 QDir dir(inDir, PLUGIN_GLOB, 00229 QDir::Name | QDir::IgnoreCase, 00230 QDir::Files | QDir::Readable); 00231 if (!dir.exists()) return ""; 00232 00233 file = dir.filePath(QFileInfo(soname).fileName()); 00234 00235 if (QFileInfo(file).exists() && QFileInfo(file).isFile()) { 00236 00237 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00238 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile: " 00239 << "found trivially at " << file << endl; 00240 #endif 00241 00242 return file; 00243 } 00244 00245 for (unsigned int j = 0; j < dir.count(); ++j) { 00246 file = dir.filePath(dir[j]); 00247 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) { 00248 00249 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00250 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile: " 00251 << "found \"" << soname << "\" at " << file << endl; 00252 #endif 00253 00254 return file; 00255 } 00256 } 00257 00258 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00259 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile (with dir): " 00260 << "not found" << endl; 00261 #endif 00262 00263 return ""; 00264 00265 } else { 00266 00267 QFileInfo fi(soname); 00268 00269 if (fi.isAbsolute() && fi.exists() && fi.isFile()) { 00270 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00271 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile: " 00272 << "found trivially at " << soname << endl; 00273 #endif 00274 return soname; 00275 } 00276 00277 if (fi.isAbsolute() && fi.absolutePath() != "") { 00278 file = findPluginFile(soname, fi.absolutePath()); 00279 if (file != "") return file; 00280 } 00281 00282 std::vector<QString> path = getPluginPath(); 00283 for (std::vector<QString>::iterator i = path.begin(); 00284 i != path.end(); ++i) { 00285 if (*i != "") { 00286 file = findPluginFile(soname, *i); 00287 if (file != "") return file; 00288 } 00289 } 00290 00291 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00292 SVDEBUG << "FeatureExtractionPluginFactory::findPluginFile: " 00293 << "not found" << endl; 00294 #endif 00295 00296 return ""; 00297 } 00298 } 00299 00300 Vamp::Plugin * 00301 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, 00302 float inputSampleRate) 00303 { 00304 Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin"); 00305 00306 Vamp::Plugin *rv = 0; 00307 Vamp::PluginHostAdapter *plugin = 0; 00308 00309 const VampPluginDescriptor *descriptor = 0; 00310 int index = 0; 00311 00312 QString type, soname, label; 00313 PluginIdentifier::parseIdentifier(identifier, type, soname, label); 00314 if (type != "vamp") { 00315 SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl; 00316 return 0; 00317 } 00318 00319 QString found = findPluginFile(soname); 00320 00321 if (found == "") { 00322 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl; 00323 return 0; 00324 } else if (found != soname) { 00325 00326 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 00327 SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl; 00328 cerr << soname << " -> " << found << endl; 00329 #endif 00330 00331 } 00332 00333 soname = found; 00334 00335 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); 00336 00337 if (!libraryHandle) { 00338 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl; 00339 return 0; 00340 } 00341 00342 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) 00343 DLSYM(libraryHandle, "vampGetPluginDescriptor"); 00344 00345 if (!fn) { 00346 SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl; 00347 goto done; 00348 } 00349 00350 while ((descriptor = fn(VAMP_API_VERSION, index))) { 00351 if (label == descriptor->identifier) break; 00352 ++index; 00353 } 00354 00355 if (!descriptor) { 00356 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl; 00357 goto done; 00358 } 00359 00360 plugin = new Vamp::PluginHostAdapter(descriptor, inputSampleRate); 00361 00362 if (plugin) { 00363 m_handleMap[plugin] = libraryHandle; 00364 rv = new PluginDeletionNotifyAdapter(plugin, this); 00365 } 00366 00367 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl; 00368 00370 00371 done: 00372 if (!rv) { 00373 if (DLCLOSE(libraryHandle) != 0) { 00374 cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl; 00375 } 00376 } 00377 00378 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl; 00379 00380 return rv; 00381 } 00382 00383 void 00384 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin) 00385 { 00386 void *handle = m_handleMap[plugin]; 00387 if (handle) { 00388 // SVDEBUG << "unloading library " << handle << " for plugin " << plugin << endl; 00389 DLCLOSE(handle); 00390 } 00391 m_handleMap.erase(plugin); 00392 } 00393 00394 QString 00395 FeatureExtractionPluginFactory::getPluginCategory(QString identifier) 00396 { 00397 return m_taxonomy[identifier]; 00398 } 00399 00400 void 00401 FeatureExtractionPluginFactory::generateTaxonomy() 00402 { 00403 std::vector<QString> pluginPath = getPluginPath(); 00404 std::vector<QString> path; 00405 00406 for (size_t i = 0; i < pluginPath.size(); ++i) { 00407 if (pluginPath[i].contains("/lib/")) { 00408 QString p(pluginPath[i]); 00409 path.push_back(p); 00410 p.replace("/lib/", "/share/"); 00411 path.push_back(p); 00412 } 00413 path.push_back(pluginPath[i]); 00414 } 00415 00416 for (size_t i = 0; i < path.size(); ++i) { 00417 00418 QDir dir(path[i], "*.cat"); 00419 00420 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl; 00421 for (unsigned int j = 0; j < dir.count(); ++j) { 00422 00423 QFile file(path[i] + "/" + dir[j]); 00424 00425 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl; 00426 00427 if (file.open(QIODevice::ReadOnly)) { 00428 // cerr << "...opened" << endl; 00429 QTextStream stream(&file); 00430 QString line; 00431 00432 while (!stream.atEnd()) { 00433 line = stream.readLine(); 00434 // cerr << "line is: \"" << line << "\"" << endl; 00435 QString id = PluginIdentifier::canonicalise 00436 (line.section("::", 0, 0)); 00437 QString cat = line.section("::", 1, 1); 00438 m_taxonomy[id] = cat; 00439 // cerr << "FeatureExtractionPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl; 00440 } 00441 } 00442 } 00443 } 00444 }